Springboot数据库连接池的学习与了解
作者:互联网
背景
- 昨天学习总结了tomcat的http连接池和线程池相关的知识,总结的不是很完整, 自己知道的也比较少,总结的时候就在想tomcat针对client 端有连接池,并且通过NIO的机制, 以较少的thread数目来支撑角度的connection, 性能和并发数都不错.
- 当时就想总结一下数据库连接池, 但是这一块内容自己接触的非常少, 又没见过底层的源码,所以总结起来非常吃力,只能够将之前遇到的简单整理一下, 可能存在很多错误和缺失的地方.
参数
- springboot 内部有较多的数据库连接池的参数, 这里可以仿照一个帖子来进行简单说明
# Hikari pool https://github.com/brettwooldridge/HikariCP
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
# 连接池中允许的最小连接数。缺省值:10
spring.datasource.hikari.minimum-idle=10
# 连接池中允许的最大连接数。缺省值:10
spring.datasource.hikari.maximum-pool-size=100
# 自动提交
spring.datasource.hikari.auto-commit=true
# 一个连接idle状态的最大时长(毫秒),超时则被释放(retired),缺省:10分钟
spring.datasource.hikari.idle-timeout=30000
# 连接池名字
spring.datasource.hikari.pool-name=FlyduckHikariCP
# 一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),缺省:30分钟,建议设置比数据库超时时长少30秒
spring.datasource.hikari.max-lifetime=1800000
# 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒
spring.datasource.hikari.connection-timeout=30000
# 数据库连接测试语句
spring.datasource.hikari.connection-test-query=SELECT 1
- 需要注意的时出去着一些的配置还需要有一个脚本的配置, yaml格式里面可以进行简单说明
datasource:
type: com.zaxxer.hikari.HikariDataSource
url:
driver-class-name: oracle.jdbc.driver.OracleDriver
username:
password:
hikari:
pool-name: hikari-cp
connection-test-query: SELECT 1 From DUAL
maximum-pool-size: 50
minimum-idle: 1
- 这里可以简单总结一下之前的工作情况, 但是并不一定准确.
1. driver-class-name 需要指定数据库的连接 不同的数据库不一样.
2. 在jpa层还有一个dialect的处理, 针对不通的数据库有不同的方言, 方言会涉及一些除了标准SQL之后不同数据库之间各自独特的处理, 注意连接不同数据库时dialect 一定要设置准确,不然容易出现一些错误.
3. username password 以及url 都不需要过多解释.
4. hikari 里面会描述部分信息 pool-name 等信息. 以及最大数据库连接池数以及最小空闲数
这里简单说明一下自己的理解 可能并不是很准确:
4.1 最大数据库连接数来决定应用服务的数据库连接池能够同时管理的数据库连接数目, 这个数目不能无限制的设置,因为还要考虑数据库的情况, 并且设置过多的数据库连接可能无益于性能提升. 数据库管理特点连接和连接池管理太多连接可能有一些额外的损耗, 这里跟应用服务器的事务处理特点有关系, 如果都是短促的事务为主可以设置的连接池数目比较小写,如果都是长事务, 建议将连接池设置的大一些,避免tomcat的thread连接池处于饥饿状态无法获取数据库的连接用于持久化或者是查询操作.
4.2 最小化连接池 保证环境存在的最低连接情况, tomcat的线程池创建和销毁会有较大的资源损耗,数据库连接池的建议要更多倍于线程池的连接的建立, 需要有tcp三步握手,数据库认证以及建立连接等, 所以保持一个合适的数据库连接数目对于突发的流量洪峰应该是有好处的
4.3 关于连接池泄漏, 如果业务代码处理数据库连接之后 没有提交或者是回滚事务, 并且没有对连接进行关闭操作,会导致,数据库连接池管理线程以为该线程不能被回收进连接池供其他进程使用,如果所有的连接池都处于这种装填就会导致无法建立新的连接,出现环境宕机的情况, 需要重点关注.
查看
- 查看当前进程的连接池数量
jmap -histo `jps |grep caf-bootstrap.jar |awk '{print $1}'` |grep -i hikariDataSource
1. 注意第一个grep 可以设置为应用服务器主线程的jar包名
2. 注意需要设置jdk的bin目录到环境变量里面去
- 一般的结果会包含如下内容
- 注意第二个数字 2 就是当前jvm 里面连接池的对象数量.
- 这里一个不成熟的理解, jvm 里面连接池也是作为java对象进行管理的. 对象数量就可表达连接池的在用数量.
[root@centos76oracle19c ~]# jmap -histo `jps |grep caf-bootstrap.jar |awk '{print $1}'` |grep -i hikariDataSource
3331: 2 336 com.zaxxer.hikari.HikariDataSource
- 查看使用连接池的线程信息.
[root@centos76oracle19c ~]# jstack -l `jps |grep caf-bootstrap.jar |awk '{print $1}'` |grep -i hikari
"hikari-cp housekeeper" #73 daemon prio=5 os_prio=0 tid=0x00007ff725e34000 nid=0x236b waiting on condition [0x00007ff6cc6db000]
[root@centos76oracle19c ~]#
- 感觉如上结果就是连接池的相关管理线程.
在使用功能时 偶尔能够查询出来 在使用的数据库连接线程信息
--
"http-nio-5200-exec-2" #225 daemon prio=5 os_prio=0 tid=0x00007ff6d2fcc800 nid=0x464d runnable [0x00007ff696b89000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
at sun.nio.ch.IOUtil.read(IOUtil.java:197)
at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
- locked <0x00000007bfdd3f18> (a java.lang.Object)
at oracle.net.nt.TimeoutSocketChannel.read(TimeoutSocketChannel.java:174)
at oracle.net.ns.NSProtocolNIO.doSocketRead(NSProtocolNIO.java:555)
at oracle.net.ns.NIOPacket.readHeader(NIOPacket.java:258)
at oracle.net.ns.NIOPacket.readPacketFromSocketChannel(NIOPacket.java:190)
at oracle.net.ns.NIOPacket.readFromSocketChannel(NIOPacket.java:132)
at oracle.net.ns.NIOPacket.readFromSocketChannel(NIOPacket.java:105)
at oracle.net.ns.NIONSDataChannel.readDataFromSocketChannel(NIONSDataChannel.java:91)
at oracle.jdbc.driver.T4CMAREngineNIO.prepareForUnmarshall(T4CMAREngineNIO.java:764)
at oracle.jdbc.driver.T4CMAREngineNIO.unmarshalUB1(T4CMAREngineNIO.java:429)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:407)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:268)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:655)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:270)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:91)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:970)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1012)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1168)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3666)
at oracle.jdbc.driver.T4CPreparedStatement.executeInternal(T4CPreparedStatement.java:1426)
at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:3778)
- locked <0x00000007bfdcef70> (a oracle.jdbc.driver.T4CConnection)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1081)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.execute(ProxyPreparedStatement.java:44)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.execute(HikariProxyPreparedStatement.java)
- 使用功能操作时也会产生新的 数据库连接对象, 可以看到从2个数据库连接池对象, 变成了3个.
[root@centos76oracle19c ~]# jmap -histo `jps |grep caf-bootstrap.jar |awk '{print $1}'` |grep -i hikariDataSource
3373: 3 504 com.zaxxer.hikari.HikariDataSource
总结
- 连接池部分自己还需要多看多学习.Oracle的pga区域大小过小的话可能无法创建过多的数据库连接需要的session, 也就是说如果数据库配置不完备, springboot 设置的高了也没有意义. Oracle可以设置 session和process的参数来限制存储的数据库连接池的大小, 注意, 一定不要将数据库的session或者是process打满, 如果打满了可能就无法操作数据库了, 如果遇到了连接池泄漏除非重启应用等待连接池消退好像没有别的更好的办法了.
- pg以及mysql以及很多国产数据库都有max_connections的操作, 怀疑这里面的connections 应该是比oracle的session和process更大宏观概念的session信息. 也需要设置的打一些,不然可能会存在问题.
- 之前分析了 tomcat的线程池,本次分析了数据库的连接池, 其实产品里面还有很多其他的线程信息, 比如 redis的以及定时器计划任务,GC线程,编译线程,日志线程,类加载线程.等线程
- 等别的晚上在分析一下其他的线程 用来提高自己.
标签:java,Springboot,数据库,driver,hikari,oracle,连接池 来源: https://www.cnblogs.com/jinanxiaolaohu/p/15216869.html