详解Mybatis中的PooledDataSource

网友投稿 320 2022-07-24


目录前言PooledConnectionPooledDataSource的pushConnection()方法总结

前言

上篇java Mybatis数据源之工厂模式文章中我们介绍了Mybatis的数据源模块的DataSource接口和它对应的实现类UnpooledDataSource、PooledDataSource,这篇文章详细介绍一下PooledDataSourcePooledDataSource使用了数据库连接池可以实现数据库连接池的重复利用,还能控制连接数据库的连接上限,实现数据库连接的统一管理,缓存数据连接信息还能防止流量突发连接数据库不及时

PooledDataSource有个PoolState状态,PoolState里保存着数据库连接信息PooledConnection,PooledConnection实现InvocationHandler接口,重写invoke方法,显然这是一个代理类,使用了JDK的动态代理

PooledConnection

class PooledConnection implements InvocationHandcOdktPQEbler {

private static final Class>[] IFACES = new Class>[] { Connection.class };

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);

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

String methodName = method.getName();

if (CLOSE.equals(methodName)) {

dataSource.pushConnection(this);

return null;

}

try {

if (!Object.class.equals(method.getDeclaringClass())) {

checkConnection();

}

return method.invoke(realConnection, args);

} catch (Throwable t) {

throw ExceptionUtil.unwrapThrowable(t);

}

}

}

我们看一看到构造方法中调用了Proxy.newProxyInstance()方法来生成代理类,而重写invoke方法中如果是close()就调用pushConnection()方法直接把它放入连接池而不是关闭连接,其他情况调用checkConnection()检查连接信息,代理类调用realConnection()方法,下面就看一下pushConnection()方法

PooledDataSource的pushConnection()方法

方法的功能就是把数据库连接放入连接池中:

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()) {

cOdktPQEb conn.getRealConnection().rollback();

}

conn.getRealConnection().close();

http:// 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++;

}

}

}

从活跃连接集合中删除该连接如果PooledConnection有效,并且空闲连接数小于最大空闲连接数,就利用当前PooledConnection创建PooledConnection,放入空闲连接数集合中,方便下次使用,关闭当前PooledConnection对象的数据库连接,并对当前PooledConnection对象设置无效,最后唤醒其他等待的线程。如果空闲连接数大于最大空闲连接数了就关闭连接,设置当前连接无效如果PooledConnection无效,badConnectionCount加一,这个badConnectionCount是记录无效的数据库连接信息的

总结

本篇文章主要介绍了PooledConnection和PooledDataSource的pushConnection()方法,PooledConnection用到了jdk的动态代理,生成Connection的实现类的代理类,拦截的逻辑中对于close()方法没有真正关闭,而是把数据库连接信息放入连接池中供下次再使用,数据库连接信息放入连接池的过程是通过调用PooledDataSource的pushConnection()来完成的,具体就是从活跃连接集合中删除这个连接,然后放入空闲连接数集合中并把当前连接设置为无效。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:剖析Fork join并发框架工作窃取算法
下一篇:关于@ConditionalOnProperty的作用及用法说明
相关文章

 发表评论

暂时没有评论,来抢沙发吧~