MyBatis 源码分析 - 内置数据源 (4)

对于第一种情况,我们直接将超时连接强行中断,并进行回滚,然后复用部分字段重新创建 PooledConnection 即可。对于第二种情况,目前没有更好的处理方式了,只能等待了。下面用一段伪代码演示各种情况及相应的处理措施,如下:

if (连接池中有空闲连接) { 1. 将连接从空闲连接集合中移除 } else { if (活跃连接数未超出限制) { 1. 创建新连接 } else { 1. 从活跃连接集合中取出第一个元素 2. 获取连接运行时长 if (连接超时) { 1. 将连接从活跃集合中移除 2. 复用原连接的成员变量,并创建新的 PooledConnection 对象 } else { 1. 线程进入等待状态 2. 线程被唤醒后,重新执行以上逻辑 } } } 1. 将连接添加到活跃连接集合中 2. 返回连接

最后用一个流程图大致描绘 popConnection 的逻辑,如下:

MyBatis 源码分析 - 内置数据源

4.3 回收连接

相比于获取连接,回收连接的逻辑要简单的多。回收连接成功与否只取决于空闲连接集合的状态,所需处理情况很少,因此比较简单。下面看一下相关的逻辑。

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 PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this); state.idleConnections.add(newConn); // 复用时间信息 newConn.setCreatedTimestamp(conn.getCreatedTimestamp()); newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp()); // 将原连接置为无效状态 conn.invalidate(); // 通知等待的线程 state.notifyAll(); } else { // 空闲连接集合已满 state.accumulatedCheckoutTime += conn.getCheckoutTime(); // 回滚未提交的事务 if (!conn.getRealConnection().getAutoCommit()) { conn.getRealConnection().rollback(); } // 关闭数据库连接 conn.getRealConnection().close(); conn.invalidate(); } } else { state.badConnectionCount++; } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywxws.html