一、背景
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。
传统的连接机制与数据库连接池的运行机制区别

不使用连接池流程
下面以访问MySQL为例,执行一个SQL命令,如果不使用连接池,需要经过哪些流程。
不使用数据库连接池的步骤:

TCP建立连接的三次握手
MySQL认证的三次握手
真正的SQL执行
MySQL的关闭
TCP的四次握手关闭
可以看到,为了执行一条SQL,却多了非常多我们不关心的网络交互。
优点:实现简单
缺点:网络IO较多,数据库的负载较高,响应时间较长及QPS较低
应用频繁的创建连接和关闭连接,导致临时对象较多,GC频繁
在关闭连接后,会出现大量TIME_WAIT 的TCP状态(在2个MSL之后关闭)

使用连接池流程
使用数据库连接池的步骤:

第一次访问的时候,需要建立连接。 但是之后的访问,均会复用之前创建的连接,直接执行SQL语句。也就是说之执行上图中黄色的执行SQL部分

优点:较少的网络开销,系统的性能会有一个实质的提升,没了麻烦的TIME_WAIT状态

二、连接池的工作原理
1、连接池的建立
连接池中的连接不能随意创建和关闭,避免随意建立和关闭造成的系统开销。Java中很多容器用来构建连接池 Vector\Stack等

2、连接池中连接的使用管理
1) 请求连接时,先看是否有空闲连接(有就直接分配),没有空闲连接就看是否超过最大连接数(没超过就去创建连接分配),已经到了最大连接数没法创建了,那就按照最大等待事件等待旧连接释放,超时了就抛异常。
2) 释放连接时,先判断该连接的引用次数是否超过了规定值,如果超过就从连接池把这个连接删除掉(这块还没能理解)

3、连接池的关闭
应用程序退出时,关闭连接池中所有的连接,释放连接池相关的资源,该过程与创建相反。

三、连接池需要注意的事项
1、并发问题
考虑多线程环境,即并发问题,使用synchronized(java)lock(C#)关键字即可确保线程是同步的
2、事务处理
事务具有原子性。当2个线程共用一个连接Connection对象,而且各自都有自己的事务要处理时候,对于连接池是一个很头疼的问题,因为即使Connection类提供了相应的事务支持,可是我们仍然不能确定哪个数据库操作是对应哪个事务的,这是由于我们有2个线程都在进行事务操作而引起的。为此采用每一个事务独占一个连接来实现,虽然这种方法有点浪费连接池资源但是可以大大降低事务管理的复杂性。
3、连接池中连接的分配与释放
对于连接的管理可使用一个List。即把已经创建的连接都放入List中去统一管理。每当用户请求一个连接时,系统检查这个List中有没有可以分配的连接。如果有就把那个最合适的连接分配给他(如何能找到最合适的连接?);如果没有就抛出一个异常给用户,List中连接是否可以被分配由一个线程来专门管理(这个线程的具体实现是什么?)。
4、连接池的配置与维护
最小连接数 设置的少 启动就快,响应却慢。设置的多 启动就慢,响应却快。开发测试的时候设置少点, 生产环境设置多点。 最大连接数则更具实际情况。
确保连接池中的最小连接数呢?有动态和静态两种策略。动态即每隔一定时间就对连接池进行检测,如果发现连接数量小于最小连接数,则补充相应数量的新连接,以保证连接池的正常运转。静态是发现空闲连接不够时再去检查。

四、几类连接池的比较
Java应用程序开发时,常用的连接池有C3P0、DBCP、Proxool等。
springboot2.x之后,系统的默认数据源由原来的的org.apache.tomcat.jdbc.pool.DataSource更改为com.zaxxer.hikari.HikariDataSource。

1、C3P0 早期一款数据库连接池产品, Hibernate将其作为内置的数据库连接池,简单易用 稳定性好, 性能差, 架构复杂又不好重构,退出。

2、DBCP 依赖于另外一个子项目Pool,导致落伍了。2013年Pool更新,2014年DBCP更新2.0,性能尚可,但是没有优势了。

3、HikariCP 性能强劲、稳定性也不差。
性能好的原因:
1)字节码精简,CPU缓存可以加载更多的程序代码
2)优化代理和拦截器,减少代码,例如HikariCP的Statement proxy只有100行代码;
3)自定义数组类型(FastStatementList)代替ArrayList:避免每次get()调用都要进行range check,避免调用remove()时的从头到尾的扫描;
4)自定义集合类型(ConcurrentBag):提高并发读写的效率
5)其他缺陷的优化,比如对于耗时超过一个CPU时间片的方法调用的研究(但没说具体怎么优化)

4、Druid 是阿里开源的JDBC应用组件,主要特点是全面, 性能和稳定性也都不错。其组成包括3部分:
1)DruidDriver: 代理driver,能够提供基于Filter-chain模式的 插件体系
2)DruidDataSource:高效可管理的数据库连接池
3)SQLParser: 实用的SQL语法分析
Druid可以实现以下功能:
1)、监控数据库访问性能 StatFilter
2)、替换传统的C3P0、DBCP连接池中间件
3)、数据库密码加密
4)、SQL执行日志
5)、扩展JDBC

03-05 16:52