一、Druid连接池配置
JDBC连接是长连接,为了保活,连接池有4种设置,我们进行取舍时,主要是对性能、连接有效性进行平衡考虑。
- 从连接池获取连接时检查,配置参数testOnBrorow,这个配置对性能影响较大,相当于获取连接时都需要先执行一次SQL查询 ,但是连接有效性最好。
- 向连接池归还连接时检查,配置参数testOnReturn,这个配置对性能影响较大,连接有效性也不好,因为这个连接归还时检查通过,使用时还是可能不可用。
- 从连接池获取连接时进行抽查,配置参数testWhileIdle,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。这个配置对性能影响很小,且连接有效性好。
- 心跳保活检查,配置参数keepAlive,这个配置对性能影响很小,且连接有效性好
二、配置建议
版本选择
Druid版本必须选择为1.1.24版本,默认值相关的类DruidAbstractDataSource。
mysql驱动必须选择为8.0.27版本,默认值相关的类PropertyDefinitions。
我们的数据库在内网,有专业团队维护,可用性很高,考虑这种情况,我们选择的配置如下:
testOnBorrow=true
testOnReturn=false
testWhileIdle=true
keepAlive=true
timeBetweenEvictionRunsMillis=20000
validationQueryTimeout=5
validationQuery=‘select 1’
Druid还有一个BUG
另外Druid还有一个BUG,mysql数据库会优先使用pingInternal方法检查连接有效性,这样使得连接的最后一个数据包时间没有更新,导致错误关闭连接,并打印错误日志“discard long time none received connection.”。
修改办法:
在启动类增加如下代码,关闭ping探测。(在配置中心中增加参数无效)
("","false");
或者在JVM参数中配置,推荐
-=false
三、配置参数表
SDK/客户端/插件 | 必须配置参数 | 配置值 | 默认值 | 参数含义 |
druid(德鲁伊) | minEvictableIdleTimeMillis | 3min | 30min | 最小空闲时间,默认30分钟,如果连接池中非运行中的连接数大于minIdle,并且那部分连接的非运行时间大于minEvictableIdleTimeMillis,则连接池会将那部分连接设置成Idle状态并关闭;也就是说如果一条连接30分钟都没有使用到,并且这种连接的数量超过了minIdle,则这些连接就会被关闭了。 |
maxEvictableIdleTimeMillis | 5min | 420min | Druid会判断池中的连接如果非运行时间大于maxEvictableIdleTimeMillis,也会强行把它关闭,而不用判断空闲连接数是否小于minIdle; | |
timeBetweenEvictionRunsMillis | 20000 | 60000 | 有两个含义: 1) Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明 |
|
maxWait | 10s | -1 | 连接池中连接用完时,新的请求等待时间,毫秒,-1表示无限等待,直到超时为止,不能配置为-1 | |
maxWaitThreadCount | 1000 | -1 | 表示允许的最大等待连接的应用线程数 ,超过1000个时可能会在maxwait定义的值没结束就被驱逐 |
|
maxActive | 50 | 8 | 线程池中最大的连接数 | |
initialSize | 5 | 0 | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 | |
minIdle | 5 | 0 | 最小连接池数量 | |
testOnBrorow | TRUE | FALSE | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。与testWhiteIlde二选一,活跃连接数>30可设置为false,影响性能。 | |
testWhileIdle | TRUE | TRUE | 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 | |
testOnReturn | FALSE | FALSE | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 | |
keepAlive | TRUE | FALSE | 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作。版本1.1.5以上支持该参数 | |
validationQuery | select | null | 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。 | |
validationQueryTimeout | 1 | -1 | 单位:秒,检测连接是否有效的超时时间。底层调用jdbc Statement对象的void setQueryTimeout(int seconds)方法 | |
poolPreparedStatements(必须不配置) | 5 s | FALSE | 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 | |
JDBC url参数 | connectTimeout | 10s | 0 | 配置在url中,确定建立连接之前的超时(以毫秒为单位 ) |
socketTimeout | 60s | 0 | 配置在url中,等待响应超时(读取数据超时) socketTimeout 架构部内部应用<1min | |
autoReconnect | TRUE | FALSE | 当数据库连接异常中断时,是否自动重新连接? | |
characterEncoding | utf8 | null | 字符集编码 | |
useUnicode | TRUE | TRUE | 使用Unicode编码 | |
failOverReadOnly | FALSE | TRUE | 自动重连成功后,连接是否设置为只读? | |
useSSL | FALSE | TRUE | 不使用SSL |
四、MYSQL服务器配置
公司MySQL服务器配置的连接超时时间是15分钟。
配置项:wait_timeout=900
如果我们配置的minEvictableIdleTimeMillis、maxEvictableIdleTimeMillis大于15分钟,可能遇到服务器先关闭了连接,我们去使用这个连接时报错。
五、遇到的常见问题
问题1
Error attempting to get column ‘createTime’ from result set. Cause: 或者出现Cannot resolve method. Will use 'SELECT 1' instead.
检查是否使用了druid,升级druid版本至1.1.18或更高版本
问题原因及解决方法-****博客
问题2
The server time zone value 'xxxxx' is unrecognized or represents more than one time zone
解决方案:
在mysql连接字符串url中加入serverTimezone=GMT+8即可,如:url=jdbc:mysql://:3306/xxx?characterEncoding=utf8&useSSL=false&serverTimezone=GMT+8
问题3
jdbcurl中的 & 要替换成 & ,不支持& 转义符
问题4
有用到IFNULL函数的,需要注意。版本升级后有些特殊返回的值不一样。比如数据0.0,旧版本返回0,新版本返回的是0.0;还有空值场景
排查代码中是否有用到ifnull()的场景,如有用到排查数据库字段字段值是否为浮点型,升级后是否影响业务场景,如果对业务有影响,调整sql语句
开发经验:
1、开源组织定义的版本号含义 ,
主版本号 A:第一个数字,产品改动较大,可能无法向后兼容(要看具体项目)
子版本号 B:第二个数字,增加了新功能,向后兼容
修正版本号 C:第三个数字,修复 BUG 或优化代码
2、我们使用开源包时,一般可以使用到最后一个修正版本,即保持不变时,C最大的那个版本
六、参考
设计模式沉思录:一 资源池
系统优化-连接池技术原理与实现 - 掘金
连接池选择及Jedis连接池参数配置建议
连接数据库超时设置autoReconnect=true
浅析 MySQL JDBC 连接配置上的两个误区