前言
       

        本篇对java的数据库的连接池进行讲解。

        主要站在运维角度讲解主流数据库连接池的配置参数,以及常见报错场景

        

1、为什么使用数据库连接池?

        如果不使用数据库连接池,那么应用每次访问数据库都需要进行连接的创建,频繁的进行TCP握手、挥手。造成大量消耗,降低系统性能和并发能力。

        数据库连接池管理维护一定数量的数据库连接,在应用需要连接数据库的时候进行分配,极大的降低了消耗,并能更好的管理对数据库的连接。

2、什么是数据库连接池?

        下图简单介绍了数据库连接池在应用中起到的作用,以及一些常见的配置指标

运维需要java吗_java

3、数据库连接池有哪些?

        目前的数据库连接池有Hikari,druid,dbcp,tomcat-jdbc,c3p0,BoneCP,Proxool,下面分别简单介绍下

        整体来说,更为推荐Hikari 和 druid

        Hikari性能最强

        druid扩展性、监控性最强

3.1、c3p0

        历史悠久,代码及其复杂,不利于维护。并且存在deadlock的潜在风险,不建议使用

3.2、BoneCP

        现在已经不更新了,转到了HiKariCP上。不建议使用。

3.3、Proxool

        评测说在并发较高的情况下会出错,且现在维护力度已经很小,不建议使用。

3.4、dbcp

        tomcat内置的连接池,单独使用dbcp需要3个包:common-dbcp.jar,common-pool.jar,common-collections.jar
        单线程,并发量低,性能不好,适用于小型系统

3.5、tomcat-jdbc

        由于dbcp的性能不太好,apache又新开发了一款数据库连接池-tomcat jdbc pool,有的地方也称之为JDBC Connection Pool。

3.6、Hikari

        SpringBoot默认使用Hikari(springboot2.0之后)
        SpringBoot项目如果我们通过启动器starter使用JPA或者Mybatis,是默认会使用Hikari数据库连接池的,不需要引入依赖,已经在SpringBoot中包含了。
        号称最快的数据库连接池,强于性能。

3.7、druid

        Druid能够提供强大的监控和扩展功能,强项在于监控

4、数据库连接池配置

        关于各个数据库连接池的核心配置项,我这里对目前最为常用的三个数据库连接池(Druid,Hikari,DBCP)

配置分类

参数

参数描述

Druid

Hikari

DBCP

Druid能够提供强大的监控和扩展功能,强项在于监控

SpringBoot默认使用Hikari(springboot2.0之后)

SpringBoot项目如果我们通过启动器starter使用JPA或者Mybatis,是默认会使用Hikari数据库连接池的,不需要引入依赖,已经在SpringBoot中包含了。

号称最快的数据库连接池,强于性能。

tomcat内置的连接池,单独使用dbcp需要3个包:common-dbcp.jar,common-pool.jar,common-collections.jar

单线程,并发量低,性能不好,适用于小型系统

参数

描述

默认值

参数

描述

默认值

参数

描述

默认值

基础重要

获取连接超时时间

maxWait

无限

connectionTimeout

30000ms

maxWait

无限

最小连接数

minIdle

8

minimumIdle

官方推荐不设置此值,默认同最大连接数相同

10

minIdle

0

最大连接数

maxActive

8

maximumPoolSize

池中最大连接数,包括闲置和使用中的连接

10

maxActive

8

初始化连接数

initialSize

0

initialSize

0

连接最长生命周期

maxLifetime

一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired)


如果不等于0且小于30秒则会被重置回30分钟

1800000ms

连接最大空闲时间

idleTimeout

连接允许在池中闲置的最长时间

如果idleTimeout+1秒>maxLifetime 且 maxLifetime>0,则会被重置为0(代表永远不会退出);如果idleTimeout!=0且小于10秒,则会被重置为10秒

600000ms

最大空闲连接数

maxIdle

最大空闲连接:连接池中容许保持空闲状态的最大连接数量,超过的空闲连接将被释放,如果设置为负数表示不限制

8

最小空闲连接数

minIdle

最小空闲连接:连接池中容许保持空闲状态的最小连接数量,低于这个数量将创建新的连接,如果设置为0则不创建

0

其他

readOnly

从池中获取的连接是否默认处于只读模式

false

defaultReadOnly

从池中获取的连接是否默认处于只读模式

autoCommit

此属性控制从池返回的连接的默认自动提交行为

设置为false后,事务不会自动提交,导致对数据库的插入修改操作无效,但是查询和删除可以。

true

defaultAutoCommit

此属性控制从池返回的连接的默认自动提交行为

poolName

连接池的用户定义名称,主要出现在日志记录和JMX管理控制台中以识别池和池配置

HikariPool-1

连接有效性检查

有效性检查sql

validationQuery

连接有效性检查执行sql

如果为null,则下面参数不生效

testOnBorrow

testOnReturn

testWhileIdle

null

connection-test-query

数据库连接测试语句

null

validationQuery

连接有效性检查执行sql

如果为null,则下面参数不生效

testOnBorrow

testOnReturn

testWhileIdle

null

testOnBorrow

申请连接时执行validationQuery检测连接是否有效

TRUE

keepaliveTime

每隔 keepaliveTime 检查连接的有效性,如果db连接不可用,则直接关闭

0(关闭)

testOnBorrow

申请连接时执行validationQuery检测连接是否有效

true

testOnReturn

归还连接时执行validationQuery检测连接是否有效

FALSE

testOnReturn

归还连接时执行validationQuery检测连接是否有效

false

testWhileIdle

申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。

FALSE

testWhileIdle

申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。

false

timeBetweenEvictionRunsMillis

1) Destroy线程会检测连接的间removeAbandoned隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。2) testWhileIdle的判断依据

60000

timeBetweenEvictionRunsMillis

在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位. 如果设置为非正数,则不运行空闲连接回收器线程

-1

minEvictableIdleTimeMillis

连接保持空闲而不被驱逐的最小时间

300000

minEvictableIdleTimeMillis

连接保持空闲而不被驱逐的最小时间

异常调试

removeAbandoned

用来关闭长时间不使用的连接。RemoveAbandanded功能不建议在生产环境中使用,仅用于连接泄露检测诊断

FALSE

removeAbandoned

用来关闭长时间不使用的连接。RemoveAbandanded功能不建议在生产环境中使用,仅用于连接泄露检测诊断

FALSE

removeAbandonedTimeout

打开RemoveAbandanded功能,超过这个时间则会关闭连接,单位秒

removeAbandonedTimeout

打开RemoveAbandanded功能,超过这个时间则会关闭连接,单位秒

logAbandoned

关闭abanded连接时输出错误日志

logAbandoned

关闭abanded连接时输出错误日志

5、常见数据库连接池报错

5.1、获取数据库连接超时

        原因分析:

        1、瞬间并发突增导致连接被占满

        2、出现了慢SQL。或者连接泄漏

5.1.1、Druid

com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60000, active 20, maxActive 20, creating 0

        报错解读分析:

                当前连接池活动连接数为20,最大连接数限制为20,所以没有空闲连接能进行分配,新的请求进来,等了60秒(最大等待时间)之后,抛出了异常

        异常处理解决:

                1、调大最大连接数:

                maxActive = 30

                2、打开连接回收机制:

                removeAbandoned = true 【开启超时回收】
                removeAbandonedTimeout = 180 【超过180秒则进行回收】
                logAbandoned = true 【回收的时候打印相关日志】

        如下就是连接超过removeAbandonedTimeout设置的时间,断开连接之后打印的日志,会打印出对应线程的堆栈先,就可以看出是哪个地方有长时间不释放的数据库连接。

运维需要java吗_Hikari_02

5.1.2、Hikari

Unable to acquire JDBC Connection Connection is not available, request timed out after 30000ms.

        报错解读分析:

                等待分配数据库连接30秒之后超时报错

        异常处理解决:

                1、调大最大连接数:

                maximum-pool-size: 20

当然 最重要的还是优化代码

5.2、获取到无效连接

5.2.1、Druid

The last packet successfully received from the server was 1,855,774 milliseconds ago. The last packet sent successfully to the server was 1,855,775 milliseconds ago.

        报错解读分析:

                获取到的数据库连接已经无效,并列出了最后一次成功接收和发送数据的时间间隔

        异常处理解决:

                1、设置连接有效性检查,但会对性能造成影响

                        validationQuery=select 1
                        testWhileIdle=true
                        testOnBorrow=true
                        testOnReturn=true

                2、调整数据库超时配置

                        核查应用到数据库整条链路上的超时时间(中间可能经过负载均衡以及数据库中间件mycat等),整个数据库调用链路超时设置,应该从前到后,超时时间越来越大

                        如MYSQL端的wait_timeout

5.2.2、Hikari

The last packet successfully received from the server was 212,079 milliseconds ago. The last packet sent successfully to the server was 3,004 milliseconds ago.). Possibly consider using a shorter maxLifetime value.|

Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@72b70c61 (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value

运维需要java吗_运维_03

        报错解读分析:

                这两条报错都可以看出是当前获取的连接已经不再有效

        异常处理解决:

                1、数据库连接池设置的连接存活时间超过了数据库端的超时时间,那么调小maxLifetime,但是这种情况较为少见,因为一般数据库端都会是8小时,而Hikari默认是30分钟

                2、数据库端有定时任务kill掉一定时间不活动的数据库连接,或者别的配置(网络,负载均衡,服务器tcp_keepalive_time配置等等原因)导致数据库连接被断掉,也是调小maxLifetime

                建议调整成30秒比较合适