public classPooledDataSource implements DataSource {private static final Log log = LogFactory.getLog(PooledDataSource.class);
//PollState 充当锁对象,这个对象中也有例如 空闲连接集合,活跃链接集合,请求的数量,等一些变量private final PoolState state = new PoolState(this);
//PolledDataSource中的数据源也是使用的UnpolledDataSource对象来实现的privatefinal UnpooledDataSource dataSource;//OPTIONAL CONFIGURATION FIELDS 线程池的最大活跃数量,最大空闲数量,等待时间等等。。。
protected int poolMaximumActiveConnections = 10;protected int poolMaximumIdleConnections = 5;protected int poolMaximumCheckoutTime = 20000;protected int poolTimeToWait = 20000;protected int poolMaximumLocalBadConnectionTolerance = 3;protected String poolPingQuery = "NO PING QUERY SET";protectedboolean poolPingEnabled;protected intpoolPingConnectionsNotUsedFor;
//url+username+password连接起来的字符串的hashcode值private intexpectedConnectionTypeCode;publicPooledDataSource() {
dataSource= newUnpooledDataSource();
}publicPooledDataSource(UnpooledDataSource dataSource) {this.dataSource =dataSource;
}publicPooledDataSource(String driver, String url, String username, String password) {
dataSource= newUnpooledDataSource(driver, url, username, password); expectedConnectionTypeCode=assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
}
//获取连接connection
@OverridepublicConnection getConnection() throws SQLException {returnpopConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();
}
@OverridepublicConnection getConnection(String username, String password) throws SQLException {returnpopConnection(username, password).getProxyConnection();
}
//线程安全的获取连接的方法(供PooledConnection中调用) synchronizedprotected voidpushConnection(PooledConnection conn) throws SQLException {
//所对象为PoolState
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++;
}
}
}privatePooledConnection popConnection(String username, String password) throws SQLException {
boolean countedWait= false;
PooledConnection conn= null;long t =System.currentTimeMillis();int localBadConnectionCount = 0;while (conn == null) {
synchronized (state) {
//如果state中空闲的连接不为空时,直接从state中的idelConnections集合中获取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{
//state中的idelConnections集合中没有连接connection了,判断活跃的connection是否小于最大活跃线程数,小于的话就新建一个connection//Pool does not have available connection
if (state.activeConnections.size()
conn = new PooledConnection(dataSource.getConnection(), this);if(log.isDebugEnabled()) {
log.debug("Created connection" + conn.getRealHashCode() + ".");
}
}else{
//当前活跃的connection数大于最大活跃connection数是,表明不能新建connection,这种情况下,会判断是否已经超过设定的时间20s,如果超过,会根据是否自动commit,
/不是自动提交,会进行rollback操作//Cannot create new connection
PooledConnection oldestActiveConnection = state.activeConnections.get(0);long longestCheckoutTime =oldestActiveConnection.getCheckoutTime();if (longestCheckoutTime >poolMaximumCheckoutTime) {//判断是否超时//Can claim overdue connection
state.claimedOverdueConnectionCount++;
state.accumulatedCheckoutTimeOfOverdueConnections+=longestCheckoutTime;
state.accumulatedCheckoutTime+=longestCheckoutTime;
state.activeConnections.remove(oldestActiveConnection);if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {//判断是否设置了自动提交,不是自动提交的话,会进行rollbacktry{
oldestActiveConnection.getRealConnection().rollback();
}catch(SQLException e) {/*Just log a message for debug and continue to execute the following
statement like nothing happend.
Wrap the bad connection with a new PooledConnection, this will help
to not intterupt current executing thread and give current thread a
chance to join the next competion 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");
}
}
//将之前rollback的connection进行处理,重新生成一个connection,并设置创建时间和最后使用时间
conn= new PooledConnection(oldestActiveConnection.getRealConnection(), this);
conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp());
conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp());
oldestActiveConnection.invalidate();if(log.isDebugEnabled()) {
log.debug("Claimed overdue connection" + conn.getRealHashCode() + ".");
}
}else{
//当活跃connection的集合中第一个connection不符合超时,则进行等待wait//Must wait
try{if (!countedWait) {
state.hadToWaitCount++;
countedWait= true;
}
//pooltimeTowait默认也是20秒if(log.isDebugEnabled()) {
log.debug("Waiting as long as" + poolTimeToWait + "milliseconds for connection.");
}long wt =System.currentTimeMillis();
state.wait(poolTimeToWait);
state.accumulatedWaitTime+= System.currentTimeMillis() -wt;
}catch(InterruptedException e) {break;
}
}
}
}
//经过以上处理,如果conn仍然没有值,则会循环走一行流程,第二次一定会获取到conn对象(默认的超时时间是20秒,第一次已经等待过20s了)if (conn != null) {
//判断conn是否能用 通过ping能否ping通//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++;
conn= null;if (localBadConnectionCount > (poolMaximumIdleConnections +poolMaximumLocalBadConnectionTolerance)) {if(log.isDebugEnabled()) {
log.debug("PooledDataSource: Could not get a good connection to the database.");
}throw new SQLException("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.");
}throw new SQLException("PooledDataSource: Unknown severe error condition. The connection pool returned a null connection.");
}returnconn;
}}