mybatis自带数据库连接池功能,当然也支持使用c3p0,druid等,在配置Environment-dataSource-type时,可以配置POOLED和UNPOOLED,分别对应PooledDataSourceFactory和UnPooledDataSourceFactory,前者继承后者,只是构造函数中设置dataSource为PooledDataSource,UnPooledDataSourceFactory也很简单,设置dataSource为UnPooledDataSource,并把该对象属性设置为Properties包含的key-value,这里又出现了MetaObject。DataSource主要功能就是getConnection,主要看下PooledDataSource获取connection,核心就是popConnection方法。
先看下一个辅助类PoolState:
存放了空闲连接和使用中的连接及其它参数,下面说一下popConnection流程:
1:若有空闲连接,则返回第一个(返回的是PooledConnection,不是Connection哦)
2:若当前连接数小于最大连接数,则创建PooledConnection
3:第一个使用的连接,检查是否大于最大使用时间
3.1 满足条件,收回那个连接
3.2 不满足,wait
4:后续校验
代码就不贴了,这里返回的PooledConnection,和Connection有什么关系呢?构造函数:
public PooledConnection(Connection connection, PooledDataSource dataSource) {
this.hashCode = connection.hashCode();
this.realConnection = connection;
this.dataSource = dataSource;
this.createdTimestamp = System.currentTimeMillis();
this.lastUsedTimestamp = System.currentTimeMillis();
this.valid = true;
this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);
}
在调用构造方法时,connection是dataSource.getConnection(),就是realConnection,同时又生成代理类proxyConnection,InvokeHandler就是PooledConnection,就是说PooledConnection有俩connection,一个真实的,一个代理的,代理类如何invoke呢?
如果调用close(proxyConnection的close,因为返回是proxyConnection),代理类就拦截掉了,直接把connection放入池子中。否则就让realConnection干活吧。
放入池子:空闲连接小于最大连接则放入,并notifyAll,否则拿到realConnection并close掉
protected void pushConnection(PooledConnection conn) throws SQLException {
synchronized (state) {
state.activeConnections.remove(conn);
if (conn.isValid()) {
if (state.idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
state.accumulatedCheckoutTime += conn.getCheckoutTime();
if (!conn.getRealConnection().getAutoCommit()) {
conn.getRealConnection().rollback();
}
PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
state.idleConnections.add(newConn);
newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
conn.invalidate();
if (log.isDebugEnabled()) {
log.debug("Returned connection " + newConn.getRealHashCode() + " to pool.");
}
state.notifyAll();
} else {
state.accumulatedCheckoutTime += conn.getCheckoutTime();
if (!conn.getRealConnection().getAutoCommit()) {
conn.getRealConnection().rollback();
}
conn.getRealConnection().close();
if (log.isDebugEnabled()) {
log.debug("Closed connection " + conn.getRealHashCode() + ".");
}
conn.invalidate();
}
} else {
if (log.isDebugEnabled()) {
log.debug("A bad connection (" + conn.getRealHashCode() + ") attempted to return to the pool, discarding connection.");
}
state.badConnectionCount++;
}
}
}
这就是mybatis的线程池,思考下,Session和connection的关系,connection何时close?
如果想用其他连接池,这里以druid为例,
1、pom添加druid的依赖,创建一个工厂类,继承UnPooledDataSource,构造函数将dataSource设置为DruidDataSource
public class DruidDataSourceFactory extends UnpooledDataSourceFactory {
public DruidDataSourceFactory(){
this.dataSource = new DruidDataSource();
}
}
2、添加environment,并将default指向这个id
运行,结束,整合还算方便。
注意配置文件添加了typeAliases,为了配置、使用方便,mybatis提供类型别名机制,相关代码很简单,大家自行查看一下吧
debug次数也不少了,可sql是啥样,再控制台可以显示不?下一篇我们看看mybatis的日志