数据库连接池是一个牵涉面很广的话题,对于大型系统,数据库连接池的好坏,关系到系统的性能和稳定性,因此,选好数据库连接池,是系统在架构时期的一个重要任务。
一般来讲,Java数据库连接池的选择,有两个选择,一是使用现有的开源组件,二是自己动手开发。
使用现有的开源组件,有很多可选择:
从看到网上的介绍来看,BoneCP非常不错,最新的开源数据库连接池组件中,淘宝的Druid也还很吸引人。值得一试。
自己开发就是很麻烦的事情了,要有很好的设计和编码实现,还要经过很严格、长时间的测试,但是自己实现也有好处,就是:
(1)只需要实现自己需要的部分即可,无需额外的设计和编码(开源组件都有很多其实你用不上的东西,一时半会儿还剔除不掉)
(2)可以逐步成长,逐步改善设计和实现,逐步增加功能和非功能特性,有计划的完善
(3)有了bug和新的需求不用求助社区,因为社区不是为某一个开发者服务的,你所需的特性人家不一定会愿意加进去
那么要从开源的连接池组件中选择一款来在产品中使用,需要从哪些方面考虑呢?(如果是自己开发,那么需要设计实现时考虑这些特性)。记着前一阵子发过一篇关于软件质量特性的文章,其实这里也就是这个思想的具体发挥。
(1)形态方面
(1.1)依赖
是否有依赖的JAR包?依赖包是数据库连接池组件自己的,还是第三方的?
在选择上,不依赖第三方包肯定更好,没有任何依赖包,只依赖Java自身最好
这样在系统和产品中使用就简单得多。
(1.2)环境要求
对Java版本的要求,能兼容更多Java版本肯定好,当然,如果你所开发的产品通用性方面要求少,那么能支持你产品使用的Java版本也可以。
一般来讲,能支持Java1.5/1.6/1.7最好。JDK1.4太古老了也就罢了。
(1.3)纯粹性
数据库连接池就只是完成简单的功能,最好不要附带其它的东西,其它东西需要可以单独找。
(2)配置
(1.1)可配置
都有哪些特性可以配置?一般来讲,必须的特性是数据库JDBC URL、用户名、(Schema)、访问口令、最小空闲连接数、最大连接数;
(3)获取连接的功能要求
(3.1)正常状况下获取连接当然是基本功能,问题是在出错了(例如数据库突然断开了)的状况下的处理,有几种典型情况:
1、数据库里没有池化的连接,此时数据库访问失败(例如网络故障、数据库服务器宕机),怎样处理的?
2、数据库里有一些池化的连接,此时数据库访问失败(例如网络故障、数据库服务器宕机),又是如何处理的?这个很关键。是否检查了那些池化连接的可用性?
3、数据库里有一些池化连接,但是5分钟之前数据库服务器宕机,现在数据库服务器已经完全恢复,此时又是如何处理的?
(3.2)连接分配的策略
没有到达最大连接数之前,有连接请求,直接分配新的连接,是基本功能。那么,当已经到达最大连接数,若干个连接请求,都在等待其他请求完成业务释放连接的情况下,最先释放的那个连接怎么分配?先给哪个请求者?(抢占式?先到先得?还是有策略?)
(3.3)等待连接等了很久,也没有工作线程释放连接,此时又是如何处理的?
(4)连接使用中的问题
(4.1)事务的处理
使用连接池,经常会发生的一个问题是在一个连接上设置了事务自动提交的状态为FALSE,但是代码里忘记Commit或RollBack,将连接回池,下一个得到连接的请求,处理上会受到影响,连接池有无妥善处理这个问题,也考量了实现者考量问题是否完备。
这里是完全依靠上层开发者不犯错误,还是连接池有统一的处理就非常关键。
(4.2)连接长时间不返回的处理
在连接上执行一个SQL,很长时间不返回(大概是数据库服务器出错了,死锁了等等),外边等待连接的线程等不到释放,连接池已达到最大连接数,此时怎么处理?此处关系到系统健壮性,又应该如何处理?
(4.3)statement缓存功能
数据库连接池本身解决了每次创建连接的效率问题,提高了系统数据库访问的效率,但是每次创建statement也是要消耗性能的,所以,如果系统使用SQL比较固定,可以选择采用Statement缓存,因此,要考虑Statement缓存是否支持。
Statement有可能带来内存问题,因此,除了考虑这个功能特性是否能支持,还需要考虑,在这个特性的使用者,内存是否会出现问题。
(5)关闭
(5.1)close的处理
使用close来将连接回池是通用要求,没有争议。但是一定要弄清楚的是,好的连接回池,坏的连接真正关闭和抛弃,否则,坏的连接进入池子,将来又引起麻烦。
(5.2)对池中已经建好的连接,是否长期不使用的情况下,可以回收以节省系统资源
(6)监控和日志
(6.1)状态监控
一般来讲,系统部署完毕,都要对数据库连接池做出初始的配置,包括最大连接数、最小空闲连接等等,但是使人困惑的是,配置多少好呢?很多系统对此都没有任何说法,让部署系统的人跟着感觉走,凭经验来。对一般系统,当然也无所谓,但是对某些关键系统就非常麻烦,配置的不合理,系统又不能重启,效率很差,客户抱怨,投诉电话被打爆,怎么办?
这里就体现了数据库连接池设计者和架构师的经验和水平。一般来讲,分为两个层次解决这个问题,一是连接池可以非常简单的监控池的运行状况,看看连接数是否够用,是否常常用光了所有的连接,在等待其他工作线程释放(如果有这种情况,解决的话,可能不仅仅是连接池的问题,还要配合DBA查数据库的问题),因此,连接池组件本身是否提供了一种或几种监控的方式,是一个重要的考察点。比如详细的日志、JMX、SNMP等等。
(6.2)动态调整
如上文所说,发现连接池的配置不是很合适(或不够用),需要调整,但是不允许随便重新启动系统,那么,是否有别的方法?例如通过JMX或SNMP?
(7)实际测试
上面这些特性考虑好之后,就是模拟系统实际运行的场景来进行实际的测试了,这里需要提到的是,一些开源组件做得比较好,提供了一些性能测试的测试结果,但是如果要在系统或产品里使用,需要进行更多更细致的测试,性能效率是一个方面,稳定性(有无泄漏,有无出错)是更关键的。
上面考虑的是外部特性,下面说一下其它特性
(1)是否有足够的文档?
(2)代码是否清晰易懂,将来出现问题是否能够自己动手修改
(3)开源组织是否活跃,是否能够不断完善改进
(4)复杂度。一般组件在完成要求的情况下,都是越简单越好,复杂度越高,维护改进越麻烦