今天我们就先来了解一下池化技术的必要性、原理;然后使用 Apache-common-Pool2实现一个简单的数据库连接池;接着通过实验,对比简单连接池、HikariCP、Druid 等数据库连接池的性能数据,分析实现高性能数据库连接池的关键;最后分析 Pool2 的具体源代码实现。
对象不是你想要,想要就能要
你我单身狗们经常调侃可以随便 New 出一个对象,用完就丢。但是有些对象创建的代价比较大,比如线程、tcp连接、数据库连接等对象。对于这些创建耗时较长,或者资源占用较大(占据操作系统资源,比如说线程,网络连接等)的对象,往往会引入池化来管理,减少频繁创建对象的次数,避免创建对象时的耗时,提高性能。
我们就以数据库连接 Connection 对象为例,详细说明一下创建该对象花费的时间和资源。下面是MySQL Driver 创建 Connection 对象的方法,在调用 connect 方法创建 Connection 时,会与 MySQL 进行网络通讯,建立 TCP 连接,这是极其消耗时间的。
-
connection = driver.connect(URL, props);
使用 Apache-Common-Pool2实现简易数据库连接池
下面,我们以 Apache-Common-Pool2为例来看一下池化技术相关的抽象结构。
首先了解一下Pool2中三元一体的 ObjectPool,PooledObject 和 PooledObjectFactory,对他们的解释如下:
-
ObjectPool 就是对象池,提供了
borrowObject
和returnObject
等一系列函数。 -
PooledObject 是池化对象的封装类,负责记录额外信息,比如说对象状态,对象创建时间,对象空闲时间,对象上次使用时间等。
-
PooledObjectFactory 是负责管理池化对象生命周期的工厂类,提供
makeObject
,destroyObject
,activateObject
和validateObject
等一系列函数。
上述三者都有其基础的实现类,分别是 GenericObjectPool,DefaultPooledObject 和 BasePooledObjectFactory。上一节实验中的 SimpleDatasource 就是使用上述类实现的。
首先,你要实现一个继承 BasePooledObjectFactory 的工厂类,提供管理池化对象生命周期的具体方法:
-
makeObject:创建池化对象实例,并且使用 PooledObject 将其封装。
-
validateObject:验证对象实例是否安全或者可用,比如说 Connection 是否还保存连接状态。
-
activateObject:将池返回的对象实例进行重新初始化,比如说设置 Connection是否默认AutoCommit等。
-
passivateObject:将返回给池的对象实例进行反初始化,比如说 Connection 中未提交的事务进行 Rollback等。
-
destroyObject:销毁不再被池需要的对象实例,比如说 Connection不再被需要时,调用其 close 方法。
具体的实现源码如下所示,每个方法都有详细的注释。
-
public class SimpleJdbcConnectionFactory extends BasePooledObjectFactory<Connection> {
-
....
-
@Override
-
public Connection create() throws Exception {
-
// 用于创建池化对象
-
Properties props = new Properties();
-
props.put("user", USER_NAME);
-
props.put("password", PASSWORD);
-
Connection connection = driver.connect(URL, props);
-
return connection;
-
}
-
@Override
-
public PooledObject<Connection> wrap(Connection connection) {
-
// 将池化对象进行封装,返回DefaultPooledObject,这里也可以返回自己实现的PooledObject
-
return new DefaultPooledObject<>(connection);
-
}
-
@Override
-
public PooledObject<Connection> makeObject() throws Exception {
-
return super.makeObject();
-
}
-
@Override
-
public void destroyObject(PooledObject<Connection> p) throws Exception {
-
p.getObject().close();
-
}
-
@Override
-
public boolean validateObject(PooledObject<Connection> p) {
-
// 使用 SELECT 1 或者其他sql语句验证Connection是否可用,ConnUtils代码详见Github中的项目
-
try {
-
ConnUtils.validateConnection(p.getObject(), this.validationQuery);
-
} catch (Exception e) {
-
return false;
-
}
-
return true;
-
}
-
@Override
-
public void activateObject(PooledObject<Connection> p) throws Exception {
-
Connection conn = p.getObject();
-
// 对象被借出,需要进行初始化,将其 autoCommit进行设置
-
if (conn.getAutoCommit() != defaultAutoCommit) {
-
conn.setAutoCommit(defaultAutoCommit);
-
}
-
}
-
@Override
-
public void passivateObject(PooledObject<Connection> p) throws Exception {
-
// 对象被归还,进行回收或者处理,比如将未提交的事务进行回滚
-
Connection conn = p.getObject();
-
if(!conn.getAutoCommit() &a