这篇主要看的是mybatis对于数据库连接池的实现。实现类为org.apache.ibatis.datasource.pooled包下的PooledDataSource类。 数据库连接池的代码并不难,关键在于理解他的连接和释放的策略。
连接池参数
protected int poolMaximumActiveConnections = 10;//最大存活连接数,有请求的连接
protected int poolMaximumIdleConnections = 5;//最大空闲连接数,就是没有处理请求的连接
protected int poolMaximumCheckoutTime = 20000;//强制收回时间
protected int poolTimeToWait = 20000;//获取连接等待时间
protected int poolMaximumLocalBadConnectionTolerance = 3;//如果获取到的是一个坏的连接,那么重新获取一个新的连接,次数最多为 poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance
protected String poolPingQuery = "NO PING QUERY SET";//心跳查询sql
protected boolean poolPingEnabled;//允许心跳查询
protected int poolPingConnectionsNotUsedFor;//执行心跳查询频率
还有一个属性poolState用来存放数据库状态,来看看状态类PoolState的属性
连接池状态类属性
protected final List<PooledConnection> idleConnections = new ArrayList<PooledConnection>();//空闲连接列表
protected final List<PooledConnection> activeConnections = new ArrayList<PooledConnection>();//活跃连接列表
protected long requestCount = 0;//获取到有效连接的次数
protected long accumulatedRequestTime = 0;//获取到有效连接的总耗时
protected long accumulatedCheckoutTime = 0;//收回连接的总耗时
protected long claimedOverdueConnectionCount = 0;//强制获取连接次数
protected long accumulatedCheckoutTimeOfOverdueConnections = 0;//强制收回连接占用时间之和
protected long accumulatedWaitTime = 0;//等待连接收回时间之和
protected long hadToWaitCount = 0;//等待的请求数量
protected long badConnectionCount = 0;//坏连接数量
连接池最重要的两个方法莫过于获取连接和释放连接。在池中pop和push则需要根据连接池参数来进行决策。而每次动作都会更新响应的状态。接下来看看pop和push的具体策略
pop策略
push策略
由于变量名太长,无法在流程图中标明连接池状态是如何变化的。有兴趣的可以看下源码。看下源码就能对那些状态变量有了更清晰的认识。
PooledConnection类
怎么才能在close的时候不是真的close而是调用pushConnection呢?有一种方式就是使用代理。静态代理相对麻烦,需要把除了close方法外所有方法委托给真实的Connection类。mybatis使用的是动态代理。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) {//若是close方法
dataSource.pushConnection(this);
return null;
} else {
try {
if (!Object.class.equals(method.getDeclaringClass())) {//如果不是Object定义的那些方法
checkConnection();//检查连接是否有效
}
return method.invoke(realConnection, args);//其他方法委托给realConnection
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
}
总结
连接池的代码并不难,但是可以给我们一个启发,当使用mybatis连接池遇到问题时或者需要优化、监控等,可以获取到poolState的各个属性,来做一些参考。