主要思路
1、DataSource定义连接属性url用户名密码啥的。
2、需要定义两个List,一个用来放空闲连接一个用来放工作连接。
3、使用装饰者模式代理Connecion对象,重写关闭方法。
上代码
MyDataSource
1、自定义MyDataSourceInterface继承Java的DataSource接口,默认实现他的方法因为我们只需要重写getConnection方法就好了。
2、MyAbstractDataSource实现MyDataSourceInterFace接口重写getConnection方法,从MySQL获得的连接。
3、MyDataSource继承MyAbstractDataSource重写getConnection方法,从线程池获得连接的方法。
MyDataSourceInterface接口
MyAbstractDataSource抽象类
MyAbstractDataSource得到连接的方法
// 重写得到连接方法
@Override
public Connection getConnection() throws SQLException {
return getConnection(username,password);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return doGetConnection(username,password);
}
private Connection doGetConnection(String username, String password) throws SQLException {
if (!initFlag) {
try {
Class.forName(driverClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
initFlag = true;
}
return DriverManager.getConnection(url, username,password);
}
MyDataSource类
MyDataSource得到连接的方法从空闲池
@Override
public Connection getConnection() throws SQLException, RuntimeException {
MyConnection connection = null;
this.init();
while (connection == null) {
// 线程同步上锁
synchronized (lock) {
// 如果空闲连接池不为空,那么就可以直接获取
if (!idlePool.isEmpty()) {
connection = idlePool.removeFirst();
} else {
// 如果工作连接数小于最大连接数就创建一个
if (workPool.size() < super.getMaxActive()) {
connection = new MyConnection(this,
super.getConnection());
}
// 否则不能创建连接的需要等待 maxWait 3000毫秒
}
if (connection == null) {
try {
long statr = System.currentTimeMillis();
lock.wait(super.getMaxWait());
long end = System.currentTimeMillis();
if ((end - statr) >= super.getMaxWait()) {
throw new RuntimeException("连接超时" + (end - statr));
}
} catch (InterruptedException e) {
e.printStackTrace();
// 如果线程被打断退出循环
break;
} catch (Exception e) {
e.printStackTrace();
// 连接超时退出循环
break;
}
}
}
}
// 连接不为空添加到工作连接
if (connection != null) {
workPool.addLast(connection);
}
return connection;
}
public void init() {
if (!initFlag) {
initLock.lock();
try {
// 初始化空闲连接池
while (idlePool.size() < super.getInitialSize()) {
try {
MyConnection connection = new MyConnection(this, super.getConnection());
idlePool.addLast(connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
initLock.unlock();
}
initFlag = true;
}
}
MyConnection
1、实现java的Connection接口,构造方法转入MyDataSource和要装饰的Connection对象
这里传入的connection对象是MySQL实现的connection对象,真正应用的还是MySQL的
Connection对象的方法,我们只是重写了关闭连接的方法
2、重写close方法,放回空闲连接池,this指向调用者谁调用closethis就指向谁
3、关于装饰者模式我百度了一下
装饰者模式也称为包装模式(Wrapper Pattern),属于结构型设计模式。
该模式对客户端透明的方式来动态的扩展对象,(对扩展开放,对修改关闭)
同时该模式也是继承关系的一种替代方法之一。
总之就是动态的给对象添加一些额外的职责,类似钢铁侠可以组装不同武器。
测试
连接测试
对比传统连接
@Test
public void testMyDataSource() throws SQLException {
String url = "jdbc:mysql://localhost:3306/java001?useServerPrepStmts=true";
String username = "root";
String password = "root";
String driverClassName = "com.mysql.cj.jdbc.Driver";
myDataSource.setUrl(url);
myDataSource.setUsername(username);
myDataSource.setPassword(password);
myDataSource.setDriverClassName(driverClassName);
Connection connection = myDataSource.getConnection();
System.out.println("使用连接池后空闲连接池的数量" + myDataSource.getIdlePool().size());
System.out.println(connection);
connection.close();
System.out.println("关闭连接后空闲连接池的数量" + myDataSource.getIdlePool().size());
System.out.println(myDataSource);
long start = System.nanoTime();
for (int i = 0; i < 500; i++) {
Connection connection1 = myDataSource.getConnection();
connection1.close();
}
long end = System.nanoTime();
System.out.println("MyDataSource:" + (end - start));
start = System.nanoTime();
for (int i = 0; i < 500; i++) {
Connection connection1 = DriverManager.getConnection(url, username, password);
connection1.close();
}
end = System.nanoTime();
System.out.println("DriverManager:" + (end - start));
}
输出结果:
超时测试
最大连接是30
最大等待时间3000毫秒
druid连接池
@Test
public void testDruidMaxWait() throws SQLException, InterruptedException {
List<Connection> list = new ArrayList<>();
for (int i = 0; i < 31; i++) {
Connection connection = JDBCUtil.getConnection();
list.add(connection);
}
System.out.println(list.size());
}
输出结果:
MyDatasource
@Test
public void testMaxWait() throws SQLException, InterruptedException {
myDataSource.setUrl(url);
myDataSource.setUsername(username);
myDataSource.setPassword(password);
myDataSource.setDriverClassName(driverClassName);
LinkedList<Connection> list = new LinkedList<>();
for (int i = 0; i < 31; i++) {
Connection connection = myDataSource.getConnection();
list.add(connection);
}
System.out.println(list.size());
}
输出结果:
end