/** * Constructor for SimplePooledConnection that uses the Connection and PooledDataSource passed in. * 创建连接 * * @param connection - the connection that is to be presented as a pooled connection * @param dataSource - the dataSource that the connection is from */ publicPooledConnection(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); }
/** * Invalidates the connection. * 废弃该连接 设置连接未不可用 */ publicvoidinvalidate() { valid = false; } /** * Method to see if the connection is usable. * 检查连接是否可用 连接可用并且能够被ping, * 1.判断 valid 字段 * 2.向数据库中发送检测测试的SQL,查看真正的连接还是否有效 * @return True if the connection is usable */ publicbooleanisValid() { return valid && realConnection != null && dataSource.pingConnection(this); } /** * 检查连接 * @throws SQLException */ privatevoidcheckConnection()throws SQLException { if (!valid) { thrownewSQLException("Error accessing PooledConnection. Connection is invalid."); } } }
invok代理方法
该方法是 proxyConnection 这个连接代理对象的真正代理逻辑,它会对 close 方法进行代理,并且在调用真正的连接之前对连接进行检测。
/** * This is a simple, synchronous, thread-safe database connection pool. * <p> * 简单的 带有锁的 线程安全的 数据库连接池 * * @author Clinton Begin */ publicclassPooledDataSourceimplementsDataSource {
//等待个数 booleancountedWait=false; // PooledConnection 对象 PooledConnectionconn=null; //耗时计算 longt= System.currentTimeMillis(); // 无效的连接个数 intlocalBadConnectionCount=0; //自旋 while (conn == null) { synchronized (state) { // 检测是否还有空闲的连接 if (!state.idleConnections.isEmpty()) { // Pool has available connection // 连接池中还有空闲的连接,则直接获取连接返回 conn = state.idleConnections.remove(0); if (log.isDebugEnabled()) { log.debug("Checked out connection " + conn.getRealHashCode() + " from pool."); } } else { // 连接池中已经没有空闲连接了 // Pool does not have available connection if (state.activeConnections.size() < poolMaximumActiveConnections) { // Can create new connection // 活跃的连接数没有达到最大值,则创建一个新的数据库连接 conn = newPooledConnection(dataSource.getConnection(), this); if (log.isDebugEnabled()) { log.debug("Created connection " + conn.getRealHashCode() + "."); }
} else { // Cannot create new connection // 如果活跃的连接数已经达到允许的最大值了,则不能创建新的数据库连接 // 获取最先创建的那个活跃的连接 PooledConnectionoldestActiveConnection= state.activeConnections.get(0); longlongestCheckoutTime= oldestActiveConnection.getCheckoutTime(); // 检测该连接是否超时 if (longestCheckoutTime > poolMaximumCheckoutTime) { // 如果该连接超时,则进行相应的统计 // Can claim overdue connection //超时连接个数统计 state.claimedOverdueConnectionCount++; //统计过期的连接超时时间 state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime; //统计超时时间 state.accumulatedCheckoutTime += longestCheckoutTime; // 将超时连接移出 activeConnections 集合 state.activeConnections.remove(oldestActiveConnection); //如果没有设置自动提交 if (!oldestActiveConnection.getRealConnection().getAutoCommit()) { try { // 如果超时未提交,则自动回滚 oldestActiveConnection.getRealConnection().rollback(); } catch (SQLException e) { /* Just log a message for debug and continue to execute the following statement like nothing happened. Wrap the bad connection with a new PooledConnection, this will help to not interrupt current executing thread and give current thread a chance to join the next competition for another valid/good database connection. At the end of this loop, bad {@link @conn} will be set as null. */ log.debug("Bad connection. Could not roll back"); } } // 创建新的 PooledConnection 对象,但是真正的数据库连接并没有创建 //刚刚获取的真实连接 新瓶装旧酒 conn = newPooledConnection(oldestActiveConnection.getRealConnection(), this); //设置创建时间 conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp()); //设置最后使用时间 conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp()); // 设置该超时的旧的连接为无效 oldestActiveConnection.invalidate(); if (log.isDebugEnabled()) { log.debug("Claimed overdue connection " + conn.getRealHashCode() + "."); } } else { //如果第一个连接还没有超时,说明其他的都没有超时,只能等待了 // Must wait try { //等待个数统计 if (!countedWait) { //等待计数 state.hadToWaitCount++; //下次不进行计数 countedWait = true; } if (log.isDebugEnabled()) { log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection."); } longwt= System.currentTimeMillis(); //超时等待 阻塞等待 state.wait(poolTimeToWait); //统计等待的时长 state.accumulatedWaitTime += System.currentTimeMillis() - wt; } catch (InterruptedException e) { //异常退出 break; } } } } // 已经获取到连接,如果连接不为空 if (conn != null) { // ping to server and check the connection is valid or not //连接状态可用 if (conn.isValid()) { // 如果连连接有效,事务未提交则回滚 if (!conn.getRealConnection().getAutoCommit()) { //进行回滚 恢复到最初状态 conn.getRealConnection().rollback(); } //设置连接类型 conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password)); //设置检查超时的时间 conn.setCheckoutTimestamp(System.currentTimeMillis()); //设置最后使用时间 conn.setLastUsedTimestamp(System.currentTimeMillis()); // 把连接加入到活跃集合中去 state.activeConnections.add(conn); //统计请求计数 state.requestCount++; //统计请求时长 state.accumulatedRequestTime += System.currentTimeMillis() - t; } else { //如果验证连接失败 if (log.isDebugEnabled()) { log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection."); } //统计错误连接个数 state.badConnectionCount++; localBadConnectionCount++; //连接置为null 进行GC conn = null; //无效连接个数 > 最大空闲连接数 + 失败尝试次数 //大部分无效连接,可以停止服务了 if (localBadConnectionCount > (poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance)) { if (log.isDebugEnabled()) { log.debug("PooledDataSource: Could not get a good connection to the database."); } //抛异常 因为获取的都是不可用的连接 thrownewSQLException("PooledDataSource: Could not get a good connection to the database."); } } } }
} //如果连接还未空 if (conn == null) { if (log.isDebugEnabled()) { log.debug("PooledDataSource: Unknown severe error condition. The connection pool returned a null connection."); } //抛出异常 thrownewSQLException("PooledDataSource: Unknown severe error condition. The connection pool returned a null connection."); }
/** * Method to check to see if a connection is still usable * 向数据库发送测试 SQL 来检测真正的数据库连接是否可用 * @param conn - the connection to check * @return True if the connection is still usable */ protectedbooleanpingConnection(PooledConnection conn) { // 结果 booleanresult=true;
try { // 检测真正的数据库连接是否已经关闭 result = !conn.getRealConnection().isClosed(); } catch (SQLException e) { if (log.isDebugEnabled()) { log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage()); } result = false; } // 如果真正的数据库连接还没关闭 if (result) { // 是否执行测试 SQL 语句 if (poolPingEnabled) { // 长时间(poolPingConnectionsNotUsedFor 指定的时长)未使用的连接,才需要ping操作来检测连接是否正常 if (poolPingConnectionsNotUsedFor >= 0 && conn.getTimeElapsedSinceLastUse() > poolPingConnectionsNotUsedFor) { try { if (log.isDebugEnabled()) { log.debug("Testing connection " + conn.getRealHashCode() + " ..."); } // 发送测试 SQL 语句执行 ConnectionrealConn= conn.getRealConnection(); try (Statementstatement= realConn.createStatement()) { statement.executeQuery(poolPingQuery).close(); } //回滚 if (!realConn.getAutoCommit()) { realConn.rollback(); } result = true; if (log.isDebugEnabled()) { log.debug("Connection " + conn.getRealHashCode() + " is GOOD!"); } } catch (Exception e) { log.warn("Execution of ping query '" + poolPingQuery + "' failed: " + e.getMessage()); try { //关闭真实连接 conn.getRealConnection().close(); } catch (Exception e2) { //ignore } result = false; if (log.isDebugEnabled()) { log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage()); } } } } } return result; }