# 各种数据库连接池对比
# 主要功能对比
Hikari | Druid | BoneCP | DBCP | C3P0 | Tomcat-Jdbc | |
---|---|---|---|---|---|---|
线程同步 | 多线程 异步 | 多线程 异步 | 单线程 | 单线程 | 单线程 | 多线程,异步 |
LRU | 否 | 是 | 否 | 是 | 否 | 是 |
PSCache | 否 | 是 | 是 | 是 | 是 | 是 |
ExceptionSorter | 否 | 是 | 否 | 否 | 否 | 否 |
更新维护 | 是 | 是 | 否 | 否 | 否 | 是 |
扩展性 | 好 | 好 | 好 | 弱 | 弱 | 弱 |
监控 | jmx/metrics | jmx/log/http | jmx | jmx | jmx/log | jmx |
SQL拦截及解析 | 否 | 是 | 否 | 否 | 否 | 否 |
代码复杂度 | 简单 | 复杂 | 简答 | 中等,超过60个类 | 复杂 | 简单,8个核心类 |
特点 | 优化力度大 功能简单 起源于BoneCP | 阿里开源 功能全面 为监控而生 文档详细 | 性能是C3P0等 的25倍左右 | 依赖于apache-common-pool | 历史久远, 代码逻辑复杂, 不移维护 | 异步, 高性能, DBCP连接池 的备选方案 |
连接池管理 | ThreadLocal/ CopyOnWrite ArrayList | 数组/ CopyOnWrite ArrayList | Linked Blocking Queue | 堆栈 | 队列 | FairBlockingQueue |
Tomcat数据源,JNDI | 支持JNDI配置 | 支持JNDI配置 | 支持JNDI配置 | 支持JNDI配置, 需要加入jconn3.jar | 数据和JNDI绑定, 支持JDBC2和JDBC3的扩展 | 支持JNDI配置,Tomcat的一个模块 |
# LRU
LRU是一个性能关键指标,特别Oracle,每个Connection对应数据库端的一个进程,如果数据库连接池遵从LRU,有助于数据库服务器优化,这是重要的指标。在测试中,Druid、DBCP、Proxool是遵守LRU的。BoneCP、C3P0则不是。BoneCP在mock环境下性能可能好,但在真实环境中则就不好了。
# PSCache
PSCache是数据库连接池的关键指标。在Oracle中,类似SELECT NAME FROM USER WHERE ID = ?这样的SQL,启用PSCache和不启用PSCache的性能可能是相差一个数量级的。Proxool是不支持PSCache的数据库连接池,如果你使用Oracle、SQL Server、DB2、Sybase这样支持游标的数据库,那你就完全不用考虑Proxool。
# ExceptionSorter
ExceptionSorter是一个很重要的容错特性,如果一个连接产生了一个不可恢复的错误,必须立刻从连接池中去掉,否则会连续产生大量错误。这个特性,目前只有JBossDataSource和Druid实现。Druid的实现参考自JBossDataSource,经过长期生产反馈补充。
# 什么是数据库连接池?
在一定程度上可以明显优化服务器应用程序的性能,提高程序执行效率和降低系统资源开销。这里所说的池是一种广义上的池,比如数据库连接池、线程池、内存池、对象池等。其中,对象池可以看成保存对象的容器,在进程初始化时创建一定数量的对象。需要时直接从池中取出一个空闲对象,用完后并不直接释放掉对象,而是再放到对象池中以方便下一次对象请求可以直接复用。其他几种池的设计思想也是如此,池技术的优势是,可以消除对象创建所带来的延迟,从而提高系统的性能。
# 为什么要使用数据库连接池?
数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。 一个数据库连接对象均对应一个物理数据库连接,每次操作都打开一个物理连接,使用完都关闭连接,这样造成系统的性能低下。 数据库连接池的解决方案是在应用程序启动时建立足够的数据库连接,并讲这些连接组成一个连接池(简单说:在一个“池”里放了好多半成品的数据库联接对象),由应用程序动态地对池中的连接进行申请、使用和释放。对于多于连接池中连接数的并发请求,应该在请求队列中排队等待。并且应用程序可以根据池中连接的使用率,动态增加或减少池中的连接数。 连接池技术尽可能多地重用了消耗内存地资源,大大节省了内存,提高了服务器地服务效率,能够支持更多的客户服务。通过使用连接池,将大大提高程序运行效率,同时,我们可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。
# 不使用数据库连接池需要哪些步骤?
TCP建立连接的三次握手
MySQL认证的三次握手
真正的SQL执行
MySQL的关闭
TCP的四次握手关闭
可以看到,为了执行一条SQL,却多了非常多我们不关心的网络交互。
优点
- 实现简单
缺点
- 网络IO较多
- 数据库的负载较高
- 响应时间较长及QPS较低
- 应用频繁的创建连接和关闭连接,导致临时对象较多,GC频繁
- 在关闭连接后,会出现大量TIME_WAIT 的TCP状态(在2个MSL之后关闭)
# 使用连接池的步骤
第一次访问的时候,需要建立连接。 但是之后的访问,一般情况下,会复用之前创建的连接,直接执行SQL语句。
优点
- 较少了网络开销
- 系统的性能会有一个实质的提升
- 没了麻烦的TIME_WAIT状态
# 连接池的工作原理
连接池的工作原理主要由三部分组成,分别为
连接池的建立
连接池中连接的使用管理
连接池的关闭
第一、连接池的建立。一般在系统初始化时,连接池会根据系统配置建立,并在池中创建了几个连接对象,以便使用时能从连接池中获取。连接池中的连接不能随意创建和关闭,这样避免了连接随意建立和关闭造成的系统开销。Java中提供了很多容器类可以方便的构建连接池,例如Vector、Stack等。
第二、连接池的管理。连接池管理策略是连接池机制的核心,连接池内连接的分配和释放对系统的性能有很大的影响。
其管理策略是:
当客户请求数据库连接时,首先查看连接池中是否有空闲连接,如果存在空闲连接,则将连接分配给客户使用;如果没有空闲连接,则查看当前所开的连接数是否已经达到最大连接数,如果没达到就重新创建一个连接给请求的客户;如果达到就按设定的最大等待时间进行等待,如果超出最大等待时间,则抛出异常给客户。
当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就从连接池中删除该连接,否则保留为其他客户服务。
该策略保证了数据库连接的有效复用,避免频繁的建立、释放连接所带来的系统资源开销。
第三、连接池的关闭。当应用程序退出时,关闭连接池中所有的连接,释放连接池相关的资源,以便连接可以返回池中重复利用。我们可以通过Connection对象的Close或Dispose方法,也可以通过C#的using语句来关闭连接。该过程正好与创建相反。
移除无效连接
无效连接,即不能正确连接到数据库服务器的连接。对于连接池来说,存储的与数据库服务器的连接的数量是有限的。因此,对于无效连接,如果如不及时移除,将会浪费连接池的空间。其实你不用担心,连接池管理器已经很好的为我们处理了这些问题。如果连接长时间空闲,或检测到与服务器的连接已断开,连接池管理器会将该连接从池中移除。
# 连接池的主要参数
最小连接数Min Pool Size: 默认为0。
是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费.
最大连接数Max Pool Size: 默认为100。
是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作
最大空闲时间 获取连接超时时间Connection Timeout:连接请求等待超时时间。默认为15秒,单位为秒。 超时重试连接次数
Pooling: 是否启用连接池。ADO.NET默认是启用连接池的,因此,你需要手动设置Pooling=false来禁用连接池。