日期:2014-05-16  浏览次数:20803 次

Java数据库连接池(二)

?

Java数据库连接池(二)

?

连接池需要解决的问题

???????? 连接池在Java应用中扮演着重要的角色,J2EE已经将连接池作为Java的一项基本规范纳入到JDBC4.0中,可见连接池的重要性。作为所有的连接池都需要面对一些共通的问题,判断或者选择连接池时,就要从这些方面去下手。

?

连接:一个连接池最基本的问题就是需要提供连接。

监控:对连接池提供有效的监控手段,监控要实现动态生效更好,可通过监控对连接使用率、可能泄露的连接、获取连接平均响应时间、获取连接最大响应时间、连接最长归还时间、创建连接总数、物理释放连接数,最好能够根据这些数据再加上时间,形成一些可视化的报表,方便开发人员或者是维护人员对连接池进行优化,以达到在建立过剩的连接情况下最大限度的达到连接重用。

高并发:必须能够应对高并发,保证连接池的稳定性的同时,达到高性能。

数据源:好的连接池应当以一种数据源的形式出现DataSource,这也是连接池的一个规范。

高性能:连接池对于应用来说扮演着重要的角色,同时也会影响到应用的性能。所以构建高性能的连接池至关重要。

缓存:缓存要从多个维度去理解,比如连接缓存、查询结果缓存。只有很好的应用缓存特性才能够构建高性能的连接池。

连接释放:连接释放应当分为两种:一种是对连接的物理释放,也就是真正的断开与数据库的连接,通常需要在关闭连接池前做的事情。一种是对连接的逻辑释放,是指通过该操作将一些用过的连接放回到连接池中。而这里的连接释放方式需要注意,应当通过Connection的close方法来进行操作,这样可以避免改变用户的编程习惯。

池:池的设计对于连接池非常重要,可以说是连接池的核心灵魂,经过认真周密设计的池,可能满足高并发、高性能、高重用性等特点。

连接可用性探测:连接池应当对自身提供给应用的连接负责,提供连接前,必须对连接是否存活,是否可用做检测,将不可用的连接进行物理释放,以免造成应用拿到不可用的连接,导致操作失败。

灵活的配置:通常连接池是需要根据具体的应用场景来进行个性化的配置,以便在任何场景下连接池都可以以最优的方式工作,这需要连接池支持当前比较常见的配置方式,例如:xml、properties、注解。提供丰富的多样的配置方式还不够,最好还要实现配置的动态生效,即不重启应用的情况下,动态使得最新的配置进行工作。

安全性:连接池是需要配置数据库的一些基本信息的,例如:url、password、username等,这些涉及到安全性,至少应当对password进行加密,防止数据库密码泄露。

学习成本:通常情况下,连接池的学习成本是基本相同的,连接池比较的通用。这里所将的学习成本是指要尽量贴近或者是完全按照规范进行实现,这样可以大大减少用户的学习成本,可保持良好的上手性和编程习惯。

集成问题:应当无缝的集成到应用当中,例如:spring、tomcat等。

多数据源:应当提供多数据源的解决方案。

分布式事务:在多数据源的场景下,应当实现分布式事务。

?

连接池的一般实现

几个概念

Connection:是指JDBC规范中的Connection,与接口java.sql.Connection相对应。与特定数据库的连接(会话)。在连接上下文中执行 SQL 语句并返回结果,一个Connection代表一个物理数据库连接。

PhysicalConnection:物理连接,真正完成数据库与应用之间的连接建立和维护,并解析语义,返回相应,一般由各个厂家在驱动程序中提供。例如:Oracle的为oracle.jdbc.driver.PhysicalConnection。

PooledConnection:是与JDBC规范中javax.sql.PooledConnection相对应,为连接池管理提供钩子 (hook) 的对象。PooledConnection 对象表示到数据源的物理连接。该连接在应用程序使用完后可以回收而不用关闭,从而减少了需要建立连接的次数。应用程序员不直接使用 PooledConnection 接口,而是通过一个管理连接池的中间层基础设施使用,例如数据库连接池。

ConnectionProxy:连接代理,一般由数据库连接池提供,完成对物理连接的包装,通过代理连接将一些操作交给物理连接去完成,一些操作自己完成,例如:close方法,一般物理连接的close方法是指物理上彻底关闭连接,而Proxy的一般实现是将该ConnectionProxy标记为闲置状态,并将其放回到连接池中,一般下次可用。

Pool:连接池的核心实现者,主要完成ConnectionProxy的存储,以及连接的获取、释放、创建、物理销毁、连接可用性探测、性能监控。连接池的核心,直接影响到连接池的高可用性、高并发、高性能等特性。

DataSource:是指JDBC规范中的DataSource,与接口java.sql.DataSource相对应。

PooledDataSource:连接池对DataSource的一种实现,意在从Pool中获取连接,达到连接的可重用性。

???????? 掌握了几个概念之后,就可以很清楚的知晓连接池的一般实现了,一般是应用获取一个数据库连接,需要通过调用PoolingDataSource的getConnection方法,getConnection方法就是从Pool中获取一个可用的连接,如果池中有现成的可用的,则直接返回,并将连接标记为繁忙状态。如果当前连接池中无可用连接,则会从驱动程序中获取一个物理连接,并将其包装为ConnectionProxy,返回到Pool中,将其标记为繁忙再次返回给应用。

???????? 而连接的关闭逻辑是这样的,应用App在试用完连接时,调用close方法进行连接的释放操作,而这时调用的是ConnectionProxy的close,ConnectionProxy方法一般是将该连接重新释放到连接中,并标记为闲置状态,以便其他线程去获取。

?

下面举个具体的例子,例如DBCP框架中的各个角色与其对应类的实现。

C3p0的实现

?

BoneCP的实现

由此可见在大部分的连接池框架中都可以找到这几个概念。

几个参数

???????? 数据库能否正常工作还要依赖具体环境和应用场景的具体配置,对于数据库连接池的调优也往往是集中在这几个参数上。这几个参数的配置在不同的应用甚至是不同的压力下,都应当有不同的配置,所以我们需要不断的测试调整这些参数以此达到数据库连接池最优。没有绝对正确的参数,只有适合某些场景下的参数,设置是相同的应用在不同的访问压力下,也应当有不同的参数配置。

???????? 虽然目前市场上Java的开源框架繁多,但是大部分的连接池配置参数都有大同小异。首先是连接池在启动时会初始化initMinNum个数据库连接,然后在应用压力逐渐上升时,不断的创建连接,直到MaxNum个,当压力回落时,会逐渐的释放连接直到闲置连接数