数据库连接池介绍(简明扼要版)

数据库连接池

为什么需要连接池

当一个数据库操作任务到来时,程序需要和数据库建立连接,进行三次握手、数据库用户验证,然后执行SQL语句,最后用户退出、四次挥手关闭连接。每次任务都执行这样的流程,那么整个流程中,真正有效而且变化的只有执行SQL语句这一步骤,而且每次建立连接、用户验证、关闭连接都耗费时间。

因此,考虑能不能将连接只创建一次,然后复用长连接执行 SQL 语句呢?这需要池化技术

池化技术可以减少资源对象的创建次数,提高程序的响应性能,特别是对高并发场景下的性能提升非常明显。

适合使用池化技术缓存的资源对象具有如下特点:

  • 对象创建时间长
  • 对象占用资源多
  • 对象创建后可以重复使用

数据库连接池

数据库连接池是程序启动时建立一定数量的数据库连接,并将这些连接组成一个连接池,当程序需要用到连接去进行数据库操作的时候,直接从连接池中获取一个连接对象使用,使用完毕后,将连接对象归还给连接池。

优点 :

(1)资源复用。避免了频繁的创建、释放连接引起的性能开销,减少系统消耗,增进系统运行环境的稳定(减少内存碎片和数据库临时线程/进程数量)。

(2)更快的系统响应速度。数据库连接池初始化完成后,直接利用现有可用连接,避免了从数据库连接初始化和释放过程的开销,从而缩减了系统整体响应时间。

(3)统一的连接管理,避免数据库连接泄漏。数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄露。

关键参数(以HikariCP为例)
  1. connectionTimeout:客户端等待池中连接的最大事件(毫秒),超时则会抛出 SQLException,最低可接受时间为 250ms,默认值为30000ms
  2. maximumPoolSize:连接池中的最大连接数。默认为 10
  3. minimumIdle:控制 HikariCP 中维护的最小空闲连接数。当空闲连接数小于 minimumIdle 并且池中的总连接数少于 maximumPoolSize 时,HikariCP 将添加其他连接直到 maximumPoolSize。为了获得最佳性能和对峰值需求的响应能力建议不要设置此值。 默认值与 maximumPoolSize 相同
  4. idleTimeout:池中连接保持空闲状态的最长时间,只有在定义的minimumIdle 小于maximumPoolSize时生效,允许的最小时间为 10000ms,默认为 600000ms.当你配置了minimumIdle 且它的值还和maximumPoolSize不同的时候,就相当于告诉HikariCP,你至少得给我创建minimumIdle 多的连接备着。但是当你的系统忙的把minimumIdle 个备着的连接都拿走使用时,此时再问HikariCP索要,它就得给你创建多于minimumIdle 的连接,除非有连接还回来,否则我就得一直给你创建新的,直到达到上限------maximumPoolSize。但是,当你的系统过了忙碌期,闲下来的时候,多创建出来的那些连接,HikariCP就得抽空给干掉,因为它只需要保留minimumIdle 个就好了,多了浪费。此时这个idleTimeout参数就有用了,它就是用来告诉HikariCP,多出来的这些连接,多长时间没再被使用,你就可以干掉了。
  5. connectionTestQuery: 用来测试连接是否可用的 SQL 查询,HikariCP 默认会使用 SELECT 1 语句进行测试,如果设置为null,则不会进行测试。
  6. maxLifetime: 最有可能出现坑的参数 .池中连接的最大生命周期,默认值为1800000ms,即30分钟。如果设置为0,表示存活时间无限大。如果不等于0且小于30秒则会被重置回30分钟。如果设置了maxLifetime,则HikariCP给池中创建的每个连接,都会定时检测,不管这个连接上一次是什么时候使用的,只要在检测时它没在使用中,就会被淘汰。注意,这就是maxLifetime参数难以被理解的原因------哪怕是一个刚用完归还的连接,不幸碰巧赶上检测了,只能说永别------使得这个参数背后的逻辑显得非常不合理。但经过搜索,作者的想法是:一个连接即使一直能用,也不应该一直存在下去,应该定时的关闭(哪怕一天关一次),好让数据库服务器那边清理掉一些浪费的资源。所以这才是maxLifetime最根本存在的原因。
连接数设置为多少才合适
  1. 经验公式,连接数=(核心数*2)+有效磁盘数。

假如服务器CPU是i7的8核,那么连接池连接数大小为 8∗2+1=9 。这仅仅是一个经验公式,具体的还要和线程池数量以及具体业务结合在一起。

  1. IO密集型任务

如果任务整体上是一个IO密集型的任务。在处理一个请求的过程中(处理一个任务),总共耗时100+5=105ms,而其中只有5ms是用于计算操作的(消耗cpu),另外的100ms等待io响应,CPU利用率为5/(100+5)。

使用线程池是为了尽量提高CPU的利用率,减少对CPU资源的浪费,假设以100%的CPU利用率来说,要达到100%的CPU利用率,对于一个CPU就要设置其利用率的倒数个数的线程数,也即1/(5/(100+5))=21,4个CPU的话就乘以4,即84,这个时候线程池要设置84个线程数,然后连接池也是设置为84个连接。

连接池和长连接的区别
  • 长连接是一些驱动、驱动架构、ORM(即Object-Relational Mapping)工具的特性,由驱动来保持连接句柄的打开,以便后续的数据库操作可以重用连接,从而减少数据库的连接开销。

  • 连接池是应用服务器的组件,它可以通过参数来配置连接数、连接检查、连接的生命周期等。

  • 连接池内的连接,其实就是长连接。

如何简单实现一个连接池

实现一个连接池,最关键的是均衡保活.连接池的"池"通过队列数据结构进行实现,队列先进先出的特性保证了使用连接的均衡性,每一条连接都可以均匀的被使用到.连接池对外提供get()和free()两个API,get()用于从队首"出队"获取一条可用连接,free()用于将使用完的连接从对尾"入队"释放到队列中。

业务代码在低峰时会降低get()动作,所以连接池中的连接在长时间不用时会导致失效,此时保活线程在监测到get()的使用频率较低时,会模拟业务程序调用get()获取连接后发送心跳包,然后再通过free()将被保活的连接放回队列中,达到连接池中所有连接保活的目的。

相关推荐
数据与人工智能律师9 分钟前
数字资产革命中的信任之锚:RWA法律架构的隐形密码
大数据·网络·人工智能·云计算·区块链
菜包eo1 小时前
二维码驱动的独立站视频集成方案
网络·python·音视频
丶意冷1 小时前
mybatisPlus分页方言设置错误问题 mybatisPlus对于Oceanbase的Oracle租户分页识别错误
java·数据库·oracle·oceanbase
yzx9910131 小时前
关于网络协议
网络·人工智能·python·网络协议
zsq1 小时前
【网络与系统安全】域类实施模型DTE
网络·安全·系统安全
国科安芯2 小时前
【AS32系列MCU调试教程】SPI调试的常见问题解析
单片机·嵌入式硬件·性能优化·硬件架构·硬件工程
桦说编程2 小时前
深入解析CompletableFuture源码实现
java·性能优化·源码
时序数据说3 小时前
为什么时序数据库IoTDB选择Java作为开发语言
java·大数据·开发语言·数据库·物联网·时序数据库·iotdb
戒不掉的伤怀3 小时前
【Navicat 连接MySQL时出现错误1251:客户端不支持服务器请求的身份验证协议;请考虑升级MySQL客户端】
服务器·数据库·mysql
cv高级工程师YKY3 小时前
服务器 - - QPS与TPS介绍
数据库