从commons-dbcp源码学习设计思路

| Comments

由于整个连接池的性能是由commons-pool决定的,有空再讲解一下commons-pool的实现,特别是1.x和2.x的区别。
此次分析的是commons-dbcp 1.x源码,对应commons-pool 1.x版本。

commons-dbcp怎样与commons-pool集成?

commons-dbcp怎样与commons-pool集成

如上图所示,集成commons-dbcp的时候采用BasicDataSource这个实现类,它的实际功能是交给PoolingDataSource的(内部是通过commons-pool来管理连接对象)。
不过,我不是很理解为什么要这么设计?

commons-dbcp的连接有什么特别?

commons-dbcp的连接有什么特别

连接这种对象有点特殊的,所以commons-dbcp提供了一些connection方面的增强特性。例如:

  • PoolGuardConnectionWrapper是最终客户端拿到的对象,能够防止多次关闭等误操作
  • PoolableConnection是PoolGuardConnectionWrapper内部的对象,可以结合pool进行管理,最大的优势就是可以保留客户端代码无需任何改动。实际上,很多自带生命周期api的对象,一旦池化之后都会考虑这么设计。
  • PoolingConnection是开启statement pool的时候PoolableConnection的内部对象,内部采用一个KeyedObjectPool进行管理(key主要是通过执行的sql语句来生成的)。不过这种对象一般不需要池化

如何优化Connection、Statement、ResultSet的生命周期管理?

jdbc的api有个非常烦人的地方,就是每个Connection、Statement、ResultSet对象都是需要关闭。所以写起来代码繁琐的,很多人就跳过这些健壮性代码。
我研究了一下dbcp的实现,发现它能够发现未关闭的Statement、ResultSet对象,并在适当的时候进行关闭。

如何优化生命周期管理

具体实现思路是这样的:

  • 需要实现生命周期管理的对象需要继承AbandonedTrace,这包括了DelegatingStatement、DelegatingResultSet、DelegatingConnection等
  • 通过DelegatingConnection生成的statement、resultset等都是带Delegating的,也就是带trace特性的。
  • 对于上图,有个特别的是DelegatingConnection的trace可能包括ResultSet,这个主要由DelegatingDatabaseMetaData产生的。因为metadata的查询不需要先有statement。
  • 处理流程调用connection.close(), 会返回到池中(见PoolableConnection), 触发PoolableConnectionFactory的passivateObject(commons-pool的内置回调),最后触发DelegatingConnection的passivate,在这里会递归检查所有的trace。
  • 注意的是,DelegatingConnection的close方法除了触发trace对象的关闭,还会关闭底层的连接对象。

Comments