文章目录

  • 背景
  • 数据连接池的技术方案
  • 需求
  • 准备工作
    • MyDataSourceInterface
    • ConnectionProxy(代理类)
    • MyAbstractDataSource(抽象类)
    • MyDataSource
  • 测试

背景

数据库连接是一种昂贵的资源,创建数据库连接是一个耗时的操作,在多线程并
发条件下尤为突出,对数据库连接的高效管理能影响到程序的性能指标,数据库
连接池正是针对这个问题提出来的。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个新连接,利用数据库连接池将明显提高对数据库操作的性能;

数据连接池的技术方案

  1. C3P0
  2. DBCP
  3. Proxool
  4. Tomcat Jdbc Pool
  5. BoneCP
  6. Druid(阿里巴巴)
  7. HikariCP(后起之秀)

数据库连接池属于一种池化技术,很多领域都会有池化技术:http访问(httpclinet)、redis访问(redisPool)、线程(线程池)等

需求

因为面试中可能会要求面试者手撕连接池,所以自己写一个提高自己的代码素养

准备工作

创建一个MyPool项目,在其下创建一个接口:MyDataSourceInterface继承DataSource

MyDataSourceInterface

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.*;
import java.util.logging.Logger;/*** @Description:继承DataSource,实现其下的方法* @CreateTime:2023/1/11 9:44* @Author:HeXin*/
public interface MyDataSourceInterface extends DataSource {@Overridedefault Connection getConnection () throws SQLException{return null;}@Overridedefault Connection getConnection (String username, String password) throws SQLException{return null;}@Overridedefault PrintWriter getLogWriter () throws SQLException{return null;}@Overridedefault void setLogWriter (PrintWriter out) throws SQLException{}@Overridedefault void setLoginTimeout (int seconds) throws SQLException{}@Overridedefault int getLoginTimeout () throws SQLException{return 0;}@Overridedefault <T> T unwrap (Class<T> iface) throws SQLException{return null;}@Overridedefault boolean isWrapperFor (Class<?> iface) throws SQLException{return false;}@Overridedefault Logger getParentLogger () throws SQLFeatureNotSupportedException{return null;}@Overridedefault ConnectionBuilder createConnectionBuilder () throws SQLException {return DataSource.super.createConnectionBuilder();}@Overridedefault ShardingKeyBuilder createShardingKeyBuilder () throws SQLException {return DataSource.super.createShardingKeyBuilder();}
}

ConnectionProxy(代理类)

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;/*** @BelongsProject: MyPool* @BelongsPackage: ConnectionProxy* @Author: HeXin* @CreateTime: 2023/1/11  10:08* @Description:采用动态代理实现对数据库连接的代理* @Version: 1.0*/
public class ConnectionProxy implements InvocationHandler {//真正的连接private Connection realConnection;//代理链接private Connection proxyConnection;//持有数据源对象private MyDataSource myDataSource;public Connection getReaslConnection () {return realConnection;}public void setRealConnection (Connection reaslConnection) {this.realConnection = reaslConnection;}public Connection getProxyConnection () {return proxyConnection;}public void setProxyConnection (Connection proxyConnection) {this.proxyConnection = proxyConnection;}public MyAbstractDataSource getMyDataSource () {return myDataSource;}public void setMyDataSource (MyDataSource myDataSource) {this.myDataSource = myDataSource;}/*** @Description: 构造方法* @CreateTime:2023/1/11 10:13* @Author:HeXin*/public ConnectionProxy (Connection realConnection, MyDataSource myDataSource) {//初始化真实连接this.realConnection = realConnection;//初始化数据源this.myDataSource = myDataSource;//初始化代理连接this.proxyConnection = (Connection)Proxy.newProxyInstance(Connection.class.getClassLoader(),new Class<?>[]{Connection.class},this);}/*** @Description: 当调用Connection对象的方法时,首先会调用该invoke方法拦截* @CreateTime:2023/1/11 10:19* @Author:HeXin*/@Overridepublic Object invoke (Object proxy, Method method, Object[] args) throws Throwable {//获取到当前调用Connection对象的方法String methodName = method.getName();if("close".equalsIgnoreCase(methodName)){//把连接归还到连接池myDataSource.closeConnection(this);return null;}return method.invoke(realConnection,args);}
}

MyAbstractDataSource(抽象类)

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;/*** @BelongsProject: MyPool* @BelongsPackage: MyDataSource* @Author: HeXin* @CreateTime: 2023/1/11  10:36* @Description:* @Version: 1.0*/
public abstract class MyAbstractDataSource implements  MyDataSourceInterface{private String url;private String driver;private String user;private String password;public String getUrl () {return url;}public void setUrl (String url) {this.url = url;}public String getDriver () {return driver;}public void setDriver (String driver) {this.driver = driver;}public String getUser () {return user;}public void setUser (String user) {this.user = user;}public String getPassword () {return password;}public void setPassword (String password) {this.password = password;}@Overridepublic Connection getConnection () throws SQLException {return getConnection(user,password);}@Overridepublic Connection getConnection (String username, String password) throws SQLException {return CreateConnection(username, password);}/*** @Description: 获取数据库连接* @CreateTime:2023/1/11 10:38* @Author:HeXin*/private Connection CreateConnection(String username,String password){Connection connection = null;try {connection = DriverManager.getConnection(url,username, password);} catch (SQLException e) {e.printStackTrace();}return connection;}
}

MyDataSource

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;/*** @BelongsProject: MyPool* @BelongsPackage: MyDataSource* @Author: HeXin* @CreateTime: 2023/1/11  10:49* @Description: 数据源的连接池* @Version: 1.0*/
public class MyDataSource extends MyAbstractDataSource{//空闲连接池private final List<ConnectionProxy> idleConnections = new ArrayList<ConnectionProxy>();//激活的连接池private final List<ConnectionProxy> activeConnections = new ArrayList<ConnectionProxy>();//最大的正在使用的连接数private int poolMaxActiveConnections = 10;//最大的空闲连接数private int poolMaxIdleConnections = 10;//从连接池中获取一个连接最大等待多少毫秒private int poolTimeToWait = 30000;//监视器对象private final Object monitor = new Object();//监视器对象private final Object watch = new Object();/*** @Description: 覆盖父类的方法,返回的是一个动态代理的连接* @CreateTime:2023/1/11 11:13* @Author:HeXin*/@Overridepublic Connection getConnection () throws SQLException {ConnectionProxy connectionProxy = getConnectionProxy(super.getUser(),super.getPassword());return connectionProxy.getProxyConnection();}/*** @Description: 获取链接* @CreateTime:2023/1/11 11:13* @Author:HeXin*/public ConnectionProxy getConnectionProxy (String username,String password) throws SQLException {boolean wait = false;ConnectionProxy connectionProxy = null;//刚开始是没有连接的while(connectionProxy == null){//做一个同步线程synchronized (monitor) {//如果空闲连接不为空,那么就可以直接获取到连接if(!idleConnections.isEmpty()){connectionProxy = idleConnections.remove(0);}else{//没有空闲连接可以使用,那么我们需要获取新的连接(创建一个连接)if(activeConnections.size()<poolMaxIdleConnections){//如果当前激活的连接数小于允许的最大连接数,那么此时可以创建一个新的连接connectionProxy = new ConnectionProxy(super.getConnection(), this);}//否则不能创建,需要等待}}if(!wait){wait = true;}if(connectionProxy == null){try {//连接对象是空,则需要等待monitor.wait(poolTimeToWait);} catch (InterruptedException e) {e.printStackTrace();//等待被线程打断,退出循环break;}}}if(connectionProxy != null){//连接对象不为空,说明已经拿到连接activeConnections.add(connectionProxy);}//返回连接return connectionProxy;}/*** @Description:释放连接(归还至连接池)* @CreateTime:2023/1/11 11:32* @Author:HeXin*/public void closeConnection(ConnectionProxy connectionProxy){synchronized (watch){//关闭连接,就是把激活状态的连接转变为空闲连接activeConnections.remove(connectionProxy);if(idleConnections.size()<poolMaxIdleConnections){idleConnections.add(connectionProxy);}//唤醒上面等待获取连接的线程monitor.notifyAll();}}
}

测试

见文章:(20条消息) 初识MySQL_ㄨ旧夢已逝,挽月归时♞的博客-CSDN博客中JDBC部分

手写实现数据库连接池相关推荐

  1. 手写java数据库连接池,自定义实现数据库连接池,兼容springboot

    一.目标 用精简的代码实现一个类似于Hikari,Druid一样的高性能数据库连接池. 二.实现思路 1:新建连接池配置类保存连接池配置. 2:实现DataSource接口. 3:新增SmpDbPoo ...

  2. 浅析Nginx中各种锁实现丨Nginx中手写一个线程池丨Nginx中反向代理,正向代理,负载均衡,静态web服务丨C++后端开发

    学会nginx中锁的使用,让你对锁豁然开朗 1. 反向代理,正向代理,负载均衡,静态web服务 2. nginx 中 accept 锁实现 自旋锁 信号量 3. nginx 中 线程池 实现以及详解虚 ...

  3. 手写一个线程池,带你学习ThreadPoolExecutor线程池实现原理

    摘要:从手写线程池开始,逐步的分析这些代码在Java的线程池中是如何实现的. 本文分享自华为云社区<手写线程池,对照学习ThreadPoolExecutor线程池实现原理!>,作者:小傅哥 ...

  4. 360mysql连接池_自己动手写个数据库连接池

    说到数据库连接池也是初学者会望而却步,认为是如何高深莫测的东西,其实可以用一句话来解释: 连接池的出现是为了用户频繁访问数据库而造成速度和性能上的迟缓才对访问数据库的方法作了一点修改,这个修改就是把原 ...

  5. 深读源码-java线程系列之自己手写一个线程池

    问题 (1)自己动手写一个线程池需要考虑哪些因素? (2)自己动手写的线程池如何测试? 简介 线程池是Java并发编程中经常使用到的技术,那么自己如何动手写一个线程池呢?本文将手把手带你写一个可用的线 ...

  6. 手写Java线程池_超详细解说_绝对能运行_代码超详细注释

    线程池 问题背景 只是单纯使用 new Thread(runnable).start(); 的方式创建线程, 将会导致严重的程序性能问题: 1.线程创建, 销毁需要消耗很大的系统资源; 2.虚拟机创建 ...

  7. 有没有想过,手写一个连接池?

    点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! 作者:矢泽妮可 来源:http://h5ip.cn/F7US 连接池的使命! 无论是线程池还是d ...

  8. 有没有想过,自己手写一个连接池?

    http://h5ip.cn/F7US 连接池的使命! 无论是线程池还是db连接池,他们都有一个共同的特性:资源复用,在普通的场景中,我们使用一个连接,它的生命周期可能是这样的: 一个连接,从创建完毕 ...

  9. Java手写线程池-第一代(原创)

    个人简介 作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门. 文章目录 个人简介 Java手写线程池(第一代) ...

最新文章

  1. hdpi、mdpi、ldpi图片规格
  2. 信号在PCB传播速度SDRAM布线(sdram布线距离主控的距离)
  3. Dijkstra算法的思想和数学归纳法
  4. 怎样更好地使用快捷键?
  5. 科大星云诗社动态20210214
  6. Spring5.0 Kafka2.11
  7. java rmi配置_Java、Spring配置RMI连接
  8. 机器学习基础:朴素贝叶斯(Machine Learning Fundamentals: Naive Bayes)
  9. 如何把pdf转换成ezd_电脑怎么把pdf转换成ppt
  10. Python——单因素方差分析表
  11. woocommerce 新增一个支付网关
  12. 听说今年金三银四变成金一银二了。
  13. Linux负载均衡解决方案 -- LVS 理论概述
  14. realme支持鸿蒙系统,骁龙888+首批搭载安卓12,realme真我GT真香售价2499元起
  15. 响应式onresize监听窗口大小
  16. yolov7利用onnx进行推理同时调用usb摄像头
  17. spo2数据集_氧仪主要测量指标分别为脉率、血氧饱和度、灌注指数(PI)
  18. 百度地图配合java 代码制作地图
  19. 分享-目前免费-简历在线制作网站
  20. 铅直渐近线、水平渐近线、斜渐近线 快速算法 笔记

热门文章

  1. validation--数据校验
  2. 互斥量、临界区、信号量、事件标志组和消息邮箱
  3. 华为nova青春版是html手机吗,华为Nova青春版这款手机作为新青年良品:麒麟935+4G+64GB+18W快充...
  4. 西安c语言培训班培训,零基础学c语言难吗 西安C语言培训班传授学习技巧
  5. 漫威超级争霸战怎么用电脑玩 漫威超级争霸战模拟器教程
  6. html编辑 手机浏览器,浏览器编辑HTML
  7. 用Python自动批量提取Tableau报表数据源中用的数据库表
  8. Cesium中添加entitie模型,实现贴地。
  9. 求任意两圆相交的面积(不限程序设计语言版本)
  10. 笔记1-----校园网进知网步骤