Mysql-Druid连接池配置
1. 背景
DRUID是阿⾥巴巴开源平台上⼀个数据库连接池实现,它结合了C3P0、DBCP、PROXOOL等DB池的优点,同时加⼊了⽇志监控,可以很好的监控DB池连接和SQL的执⾏情况,可以说是针对监控⽽⽣的DB连接池。
2. 介绍
(1)DataSource中URL重要配置参数(Spring配置前缀:spring.datasource.url)
配置缺省
说明推荐说明
serverTimezone时区Asia/Shanghai useUnicode true
characterEncoding 1、存数据
数据库在存放项⽬数据的时候
会先⽤UTF-8格式将数据解码
成字节码,然后再将解码后的
字节码重新使⽤GBK编码,并
存放到数据库中。
2、取数据
在数据库中取数据的时候,数
据库会先将数据库中的数据按
GBK格式解码成字节码,然后
再将解码后的字节码重新按
UTF-8格式编码数据,最后再
将数据返回给客户端
UTF8
useSSL true MySQL在⾼版本需要指明是否进
⾏SSL连接
false
(2)Druid重要配置参数(Spring配置前缀:spring.datasource.druid)
配置缺省值描述推荐说明
initial-size0初始化时建⽴物理连接的个数。初始
化发⽣在显⽰调⽤init⽅法,或者第
⼀次getConnection时
连接数=(核⼼数 * 2) + 有效磁盘数)
min-idle最⼩连接池数量与initialSize⼀致max-idle8最⼤连接池数量
max-wait 获取连接时最⼤等待时间,单位毫秒。配置了maxWait之后,缺省启⽤公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使⽤⾮公平锁
use-unfair-lock false如果设置了maxWait,则启⽤公平锁time-between-eviction-runs-
millis 60000
在空闲连接回收器线程运⾏期间休眠
时间,它决定线程多久验证空闲连接
或丢弃连接的频率
源码上看,是通过validation-query配置的语句语句检测连接的有效
性,如果连接失败了则丢弃
min-evictableIdle-time-millis1800000连接在池中保持空闲⽽不被回收的最⼩时间
⽤来检测连接是否有效的sql,要求
validation-query 是⼀个查询语句。如果
validationQuery为
null,testOnBorrow、
testOnReturn、testWhileIdle都不
会其作⽤false
如果检测到已知驱动后,会使⽤MySqlValidConnectionChecker
类进⾏有效检测,⾛的是ping策略,⽽不是该配置,哪怕没有配置也
会⾛默认的 “select 1”,前提是使⽤
MySqlValidConnectionChecker,不然是直接返回true的
validation-query-timeout-1检测连接超时时间虽然这⾥默认是-1,但是实际代码会设置成1s的时间
test-on-borrow false 申请连接时执⾏validationQuery检测连接是否有效,做了这个配置会降低性能
test-while-idle true 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间⼤于timeBetweenEvictionRunsMillis,执⾏validationQuery检测连接是否有效
test-on-return false 归还连接时执⾏validationQuery检测连接是否有效,做了这个配置会降低性能
pool-prepared-statements false 是否缓存preparedStatement,也就是PSCache。PSCache对⽀持游标的数据库性能提升巨⼤,⽐如说oracle。在mysql下建议关闭
max-open-prepared-statements -1
要启⽤PSCache,必须配置⼤于0,
当⼤于0
时,poolPreparedStatements⾃
动触发修改为true。在Druid中,不
会存在Oracle下PSCache占⽤内存
过多的问题,可以把这个数值配置⼤
⼀些,⽐如说100
filter-class-names
flter.stat.slow-sql-millis
3. 源码
4. 实战
4.1 数据库连接配置
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF8&useSSL=false    username: root
password: root
driver-class-name: sql.cj.jdbc.Driver
4.2 Druid配置
以数据库实例是4核8G为例(待考量):
spring:
datasource:
druid:
initial-size: 10
min-idle: 10
max-active: 25
max-wait: 60000
use-unfair-lock: true
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
5. FAQ
5.1 Druid是否有必要在设置了maxWait后,还要强制设置useUnfairLock=true?
设置后,性能会翻倍(见参考资料有赞优化),但是这样做有没有其他问题?
5.2  检测到连接达空闲时间上线时,Druid会物理关闭该连接,那么它不保证最⼩连接数吗?会重新开启新的连接吗?
(1) com.alibaba.druid.pool.DruidDataSource#getConnectionDirect
public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException {
int notFullTimeoutRetryCnt = 0;
for (;;) {
// ...
if (testOnBorrow) {
// ...
} else {
if (isClosed()) {
discardConnection(poolableConnection.holder); // 传⼊null,避免重复关闭
continue;
}
if (testWhileIdle) {
final DruidConnectionHolder holder = poolableConnection.holder;
long currentTimeMillis            = System.currentTimeMillis();
long lastActiveTimeMillis          = holder.lastActiveTimeMillis;
long lastExecTimeMillis            = holder.lastExecTimeMillis;
long lastKeepTimeMillis            = holder.lastKeepTimeMillis;
if (checkExecuteTime
&& lastExecTimeMillis != lastActiveTimeMillis) {
lastActiveTimeMillis = lastExecTimeMillis;
}
if (lastKeepTimeMillis > lastActiveTimeMillis) {
lastActiveTimeMillis = lastKeepTimeMillis;
}
long idleMillis                    = currentTimeMillis - lastActiveTimeMillis;
long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis;
if (timeBetweenEvictionRunsMillis <= 0) {
timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
}
// 如果空闲时间达到阙值
if (idleMillis >= timeBetweenEvictionRunsMillis
|| idleMillis < 0 // unexcepted branch
) {
// 检测连接是否有效
boolean validate = testConnectionInternal(poolableConnection.holder, );                        if (!validate) {
if (LOG.isDebugEnabled()) {
LOG.debug("skip not validate connection.");
}
// ⽆效则关闭连接
discardConnection(poolableConnection.holder);
continue;
druid连接池配置详解}
}
}
}
// ...
}
(2) 关闭连接后,如果当前存活数⼩于最⼩连接数
空信号的处理利⽤的是AQS的Condition.sign(),这⾥还不确定会不会开启。Condition忘记了~
public void discardConnection(DruidConnectionHolder holder) {        if (holder == null) {
return;
}
Connection conn = Connection();
if (conn != null) {
JdbcUtils.close(conn);
}
lock.lock();
try {
if (holder.discard) {
return;
}
if (holder.active) {
activeCount--;
holder.active = false;
}
discardCount++;
holder.discard = true;
if (activeCount <= minIdle) {
emptySignal();
}
} finally {
lock.unlock();
}
}
6. 参考资料
【】
【】

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。