源码地址
GitHub - alibaba/druid: 阿里云计算平台DataWorks(/document_detail/) 团队出品,为监控而生的数据库连接池
druid常用配置
# 创建DB连接4要素
=xxx
=xxx
=xxx
-class-name=
# 在数据库连接池首次创建的时候初始化几个连接
-size=5
# 最多可以激活的连接个数
-active=10
# 最小的数据库空闲连接个数
-idle=5
# 创建连接时的最大等待时长,一般这个不在意
-wait=60000
# 当执行数据库连接存活检查时,使用的通信sql语句
-query=SELECT 1 FROM DUAL
# 是不是在每次获取连接的时候都进行检查,设置为fale,对性能影响高
-on-borrow=false
# 是不是在每次归还(事务执行结束)连接的时候检查,对性能影响高
-on-return=false
# 是否在连接空闲的时候sql检查连接(这个参数只有在获取连接的时候才会使用)
-while-idle=true
# 在销毁线程中表示的是执行的时间间隔
# 在获取连接的时候,配合test-while-idle=true使用
# 表示的最小的空闲时间,大于这个时间才会进行sql检查连接
-between-eviction-runs-millis=60000
# 最小的连接空闲时间,小于这个时间不会进行回收
-evictable-idle-time-millis=3600000
# 是否开启会话保持,开启了之后如果在销毁的时候低于minidle的数量才会补充
-alive=true
# 开启了会话保持之后,对于不回收的连接
# 多长时间进行validateQuery一次校验,校验失败的话,还需要关闭异常链接并新建
-alive-between-time-millis=3600000
mysql进行jdbc连接
import .*;
public class JdbcDemo {
public static void main(String[] args) {
try {
// 加载MySQL驱动程序
("");
// 建立与MySQL的连接
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "123456";
Connection conn = (url, user, password);
// 创建Statement对象
Statement stmt = ();
// 执行查询操作
String sql = "SELECT * FROM users WHERE age > 18";
ResultSet rs = (sql);
// 处理查询结果
while (()) {
int id = ("id");
String name = ("name");
int age = ("age");
(", name=" + name + ", age=" + age);
}
// 关闭资源
if (rs != null) {
();
}
if (stmt != null) {
();
}
if (conn != null) {
();
}
} catch (ClassNotFoundException e) {
();
} catch (SQLException
e) {
();
}
}
}
druid各配置项生效原理
初始化过程
#init
= new DruidConnectionHolder[];
= new DruidConnectionHolder[];
= new DruidConnectionHolder[];
while( < ) {
try {
pyConnectInfo = ();
DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
[++] = holder;
} catch (SQLException var18) {
("init datasource error, url: " + (), var18);
if () {
connectError = var18;
break;
}
(3000L);
}
}
上面是连接池的初始化过程,数组长度是maxActive, 代表最多能拥有的连接个数,同时分为三个数组存放。
然后循环初始化数据库连接,保存至数据中,初始化的个数是initialSize个
线程任务
连接创建线程
通过信号量等控制线程运行,从而保持线程池数量。这个先不管
#run
连接销毁线程
#run
while(true) {
try {
if ( || ) {
break;
}
if ( > 0L) {
();
} else {
(1000L);
}
if (()) {
break;
}
();
} catch (InterruptedException var2) {
break;
}
}
timeBetweenEvictionRunsMillis:这个参数是标识这个线程需要sleep多久之后才能唤醒下一次销毁执行
#run
// 连接池的空闲数量 去除 最小保留的空闲连接
checkCount = - ;
// 记录空闲时长
idleMillis = currentTimeMillis - ;
// 如果空闲时长 大于最小空闲时间 并且在保留的最小空闲连接之外则移除
if (idleMillis >= ) {
if (checkTime && i < checkCount) {
[evictCount++] = connection;
continue;
}
// 如果空闲时间比最大的空闲时间还大,则直接移除
if (idleMillis > ) {
[evictCount++] = connection;
continue;
}
}
minEvictableIdleTimeMillis:空闲连接的最小保留时长,低于这个时间不会回收。高于这个时间,则移除比minIdle多出数量的连接。
maxEvictableIdleTimeMillis:默认7个小时,不管个数,空闲时间达到即移除。
通过keepalive参数进行保活
// 这个是不满足驱逐逻辑之后才执行的
// 如果设置了保持存活,且连接的空闲时间大于应该保持存活的时间了
if (keepAlive && idleMillis >= ) {
[keepAliveCount++] = connection;
}
// 需要保活,且数量低于最小空闲连接,则需要补充,就是通过唤起创建线程补充
if (keepAlive && + < ) {
needFill = true;
}
keepAlive:是否需要保持连接存活
keepAliveBetweenTimeMillis:多久进行一次保活。
keepAliveConnections:有需要保活的连接,则利用validationQuery进行保活。保活失败,则重新创建连接,依赖于上述两个配置。
needFill:如果需要补充连接的话,也会重新创建连接。依赖于keepAlive以及连接数量情况。
获取连接过程
#getConnectionDirect
// testOnBorrow 参数的使用
if () {
// 如果
boolean validate = (, );
if (validate) {
break;
}
if (()) {
("skip not validate connection.");
}
();
}
// testWhileIdle参数的使用
if (!) {
break;
}
long timeBetweenEvictionRunsMillis = ;
// 只有空闲时间大于timeBetweenEvictionRunsMillis 这个时间,才会进行验证
if (idleMillis < timeBetweenEvictionRunsMillis && idleMillis >= 0L) {
break;
}
// 验证失败就会丢弃连接
boolean validate = (, );
if (validate) {
break;
}
();
testOnBorrow:获取连接的时候进行检测
testWhileIdle:获取连接的时候,且其空闲时间大于timeBetweenEvictionRunsMillis开始进行检测