// Copyright 2007-2011 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland
// www.source-code.biz, www.inventec.ch/chdh
//
// This module is multi-licensed and may be used under the terms
// of any of the following licenses:
//
// EPL, Eclipse Public License, http://www.eclipse.org/legal
// LGPL, GNU Lesser General Public License, http://www.gnu.org/licenses/lgpl.html
// MPL, Mozilla Public License 1.1, http://www.mozilla.org/MPL
//
// Please contact the author if you need another license.
// This module is provided "as is", without warranties of any kind.
package main.java.biz.source_code.miniConnectionPoolManager;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.LinkedList;
import javax.sql.ConnectionEvent;
import javax.sql.ConnectionEventListener;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
/**
* A lightweight standalone JDBC connection pool manager.
* 一个轻量级、独立的jdbc连接池管理器
* <p>
* The public methods of this class are thread-safe.
* 在这个类中的所有的共有方法都是现成安全的
* <p>
* Home page: <a * href="http://www.source-code.biz/miniconnectionpoolmanager">www.source-code.biz/miniconnectionpoolmanager</a>
* <br>
* Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br>
* Multi-licensed: EPL / LGPL / MPL.
*/
public class MiniConnectionPoolManager {
/**PooledConnection对象的工厂*/
private ConnectionPoolDataSource dataSource;
/**连接池中的最大连接数*/
private int maxConnections;
/**超时时间设置*/
private long timeoutMs;
/**向文本输出流打印对象的格式化表示形式*/
private PrintWriter logWriter;
/**Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目*/
private Semaphore semaphore;
/**注册该对象便可获得由 PooledConnection 对象生成的事件的通知。*/
private PoolConnectionEventListener poolConnectionEventListener;
// The following variables must only be accessed within synchronized blocks. 同步块
// @GuardedBy("this") could by used in the future.
/**list of inactive PooledConnections 可用连接的集合*/
private LinkedList<PooledConnection> recycledConnections;
/**number of active (open) connections of this pool 活动中的连接数目*/
private int activeConnections;
/** true if this connection pool has been disposed true时表示没有可用的连接*/
private boolean isDisposed;
// flag to purge the connection currently beeing closed instead of recycling it 标识当前被清除而不是被回收的链接
private boolean doPurgeConnection;
// a PooledConnection which is currently within a PooledConnection.getConnection() call, or null
// PooledConnection 对象表示到数据源的物理连接。该连接在应用程序使用完后可以回收而不用关闭,从而减少了需要建立连接的次数。
private PooledConnection connectionInTransition;
/**
* Thrown in {@link #getConnection()} or {@link #getValidConnection()} when
* no free connection becomes available within <code>timeout</code> seconds.
* 在指定时间内,没有可利用的链接的时候抛错
*/
/**超时异常*/
public static class TimeoutException extends RuntimeException {
private static final long serialVersionUID = 1;
public TimeoutException() {
super("Timeout while waiting for a free database connection.");
}
public TimeoutException(String msg) {
super(msg);
}
}
/**
* Constructs a MiniConnectionPoolManager object.
* 构建一个迷你连接池管理器对象
* @param dataSource 数据资源
* the data source for the connections.
* @param maxConnections 连接数
* the maximum number of connections.
* @param timeout 等待空闲链接的最长时间
* the maximum time in seconds to wait for a free connection.
*/
public MiniConnectionPoolManager(ConnectionPoolDataSource dataSource,
int maxConnections, int timeout) {
//给相应的属性赋值
this.dataSource = dataSource;
this.maxConnections = maxConnections;
//由秒装换成毫秒
this.timeoutMs = timeout * 1000L;
try {
logWriter = dataSource.getLogWriter();
} catch (SQLException e) {
}
//最大连接数小于一的时候抛出相应的异常
if (maxConnections < 1) {
throw new IllegalArgumentException("Invalid maxConnections value.");
}
//创建具有给定的许可数和给定的公平设置的 Semaphore
//new Semaphore(初始的可用许可数目,争用时是否按照按先进先出的顺序);
semaphore = new Semaphore(maxConnections, true);
//创建相应的物理链接列表
recycledConnections = new LinkedList<PooledConnection>();
//创建监听器
poolConnectionEventListener = new PoolConnectionEventListener();
}
/**
* Constructs a MiniConnectionPoolManager object with a timeout of 60 seconds.
* 构建一个迷你连接池管理器对象在60秒的超时范围内
* @param dataSource
* the data source for the connections.
* @param maxConnections
* the maximum number of connections.
*/
public MiniConnectionPoolManager(ConnectionPoolDataSource dataSource,
int maxConnections) {
this(dataSource, maxConnections, 60);
}
/**
* Closes all unused pooled connections.
* 关闭连接池中的连接,即是将集合中的PooledConnection关闭
*/
public synchronized void dispose() throws SQLException {
//没有可用的连接
if (isDisposed) {
return;
}
//反之,标识isDisposed=true
isDisposed = true;
//sql异常为null
SQLException e = null;
//将recycledConnectins中的链接统统关闭
while (!recycledConnections.isEmpty()) {
//从链表中移除
PooledConnection pconn = recycledConnections.remove();
try {
//真正地关闭链接
pconn.close();
} catch (SQLException e2) {
if (e == null) {
e = e2;
}
}
}
if (e != null) {
throw e;
}
}
/**
* Retrieves a connection from the connection pool.
* 从连接池中检索(获取一个链接)
* <p>
* If <code>maxConnections</code> connections are already in use, the method
* waits until a connection becomes available or <code>timeout</code>
* seconds elapsed. When the application is finished using the connection,
* it must close it in order to return it to the pool.
*
* 如果所有的链接都被占用,那么该方法会会在超时范围内等待可用的链接;
* 当应用程序完成对链接的使用,它必须将链接还回到连接池中去。
* @return a new <code>Connection</code> object.
* 返回一个链接对象
* @throws TimeoutException
* when no connection becomes available within
* <code>timeout</code> seconds.
*/
/**获取链接*/
public Connection getConnection() throws SQLException {
return getConnection2(timeoutMs);
}
private Connection getConnection2(long timeoutMs) throws SQLException {
// This routine is unsynchronized, because semaphore.tryAcquire() may block.
//这个程序时异步的,因为semaphore.tryAcquire()可能引起阻塞
synchronized (this) {
//没有可用链接,抛出异常
if (isDisposed) {
throw new IllegalStateException("Connection pool has been disposed.");
}
}
try {
//当前信号量没有获得许可,抛出异常
if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
//如果在给定的等待时间内,此信号量有可用的许可并且当前线程未被中断,则从此信号量获取一个许可。
throw new TimeoutException();
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while waiting for a database connection.", e);
}
boolean ok = false;
try {
//获取链接
Connection conn = getConnection3();
ok = true;
//返回链接
return conn;
} finally {
//释放一个许可,将其返回给信号量。
if (!ok) {
semaphore.release();
}
}
}
private synchronized Connection getConnection3() throws SQLException {
//没有可用的连接
if (isDisposed) { // test again within synchronized lock
throw new IllegalStateException("Connection pool has been disposed.");
}
//表示到数据源的物理连接
PooledConnection pconn;
//可用连接数不为空的时候,从中获取一个链接
if (!recycledConnections.isEmpty()) {
pconn = recycledConnections.remove();
} else {
//获取链接
pconn = dataSource.getPooledConnection();
//注册事件
pconn.addConnectionEventListener(poolConnectionEventListener);
}
//与特定数据库的连接
Connection conn;
try {
// The JDBC driver may call
// ConnectionEventListener.connectionErrorOccurred()
// from within PooledConnection.getConnection(). To detect this
// within
// disposeConnection(), we temporarily set connectionInTransition.
connectionInTransition = pconn;
conn = pconn.getConnection();
} finally {
connectionInTransition = null;
}
//活动的链接数+1
activeConnections++;
//状态判断
assertInnerState();
//返回特定数据库的链接
return conn;
}
/**
* Retrieves a connection from the connection pool and ensures that it is valid by calling {@link Connection#isValid(int)}.
* 从数据库连接池中检索出一个链接并且保证被调用的是合法的
* <p>
* If a connection is not valid, the method tries to get another connection
* until one is valid (or a timeout occurs).
* 如果是不合法的,这个方法将试图获取另外的链接,知道合法
* <p>
* Pooled connections may become invalid when e.g. the database server is
* restarted.
* 链接可能是不合法的,当数据库服务器被重启
* <p>
* This method is slower than {@link #getConnection()} because the JDBC
* driver has to send an extra command to the database server to test the connection.
* JDBC驱动需要发送额外的命令到数据库服务器,去检测连接
* <p>
* This method requires Java 1.6 or newer.
*
* @throws TimeoutException
* when no valid connection becomes available within
* <code>timeout</code> seconds.
*/
public Connection getValidConnection() {
//毫秒 当前时间
long time = System.currentTimeMillis();
//超时时间的设置
long timeoutTime = time + timeoutMs;
int triesWithoutDelay = getInactiveConnections() + 1;
while (true) {
Connection conn = getValidConnection2(time, timeoutTime);
if (conn != null) {
//成功获得连接则返回
return conn;
}
triesWithoutDelay--;
if (triesWithoutDelay <= 0) {
triesWithoutDelay = 0;
try {
Thread.sleep(250);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while waiting for a valid database connection.",e);
}
}
//获取当前的时间
time = System.currentTimeMillis();
//判断是否已经超时,是则抛出异常
if (time >= timeoutTime) {
throw new TimeoutException("Timeout while waiting for a valid database connection.");
}
}
}
private Connection getValidConnection2(long time, long timeoutTime) {
long rtime = Math.max(1, timeoutTime - time);
Connection conn;
try {
conn = getConnection2(rtime);
} catch (SQLException e) {
return null;
}
rtime = timeoutTime - System.currentTimeMillis();
int rtimeSecs = Math.max(1, (int) ((rtime + 999) / 1000));
try {
if (conn.isValid(rtimeSecs)) {
return conn;
}
} catch (SQLException e) {
}
// This Exception should never occur. If it nevertheless occurs, it's
// because of an error in the
// JDBC driver which we ignore and assume that the connection is not
// valid.
// When isValid() returns false, the JDBC driver should have already
// called connectionErrorOccurred()
// and the PooledConnection has been removed from the pool, i.e. the
// PooledConnection will
// not be added to recycledConnections when Connection.close() is called.
// But to be sure that this works even with a faulty JDBC driver, we
// call purgeConnection().
purgeConnection(conn);
return null;
}
// Purges the PooledConnection associated with the passed Connection from the connection pool.
/**关闭当前的连接*/
private synchronized void purgeConnection(Connection conn) {
try {
doPurgeConnection = true;
// (A potential problem of this program logic is that setting the
// doPurgeConnection flag
// has an effect only if the JDBC driver calls connectionClosed()
// synchronously within
// Connection.close().)
conn.close();
} catch (SQLException e) {
}finally {
// ignore exception from close()
doPurgeConnection = false;
}
}
/**回收连接*/
private synchronized void recycleConnection(PooledConnection pconn) {
if (isDisposed || doPurgeConnection) {
disposeConnection(pconn);
return;
}
if (activeConnections <= 0) {
throw new AssertionError();
}
//活动的连接-1
activeConnections--;
//释放许可
semaphore.release();
//将连接添加到链表中
recycledConnections.add(pconn);
//判断
assertInnerState();
}
/**断开连接*/
private synchronized void disposeConnection(PooledConnection pconn) {
//销毁连接
pconn.removeConnectionEventListener(poolConnectionEventListener);
if (!recycledConnections.remove(pconn)&& pconn != connectionInTransition) {
// If the PooledConnection is not in the recycledConnections list 如果这个连接不在相应的链表中时
// and is not currently within a PooledConnection.getConnection() call 也不是当前的连接时
// we assume that the connection was active. 我们认为这个连接时活动的
if (activeConnections <= 0) {
throw new AssertionError();
}
//活动连接数-1
activeConnections--;
//释放许可
semaphore.release();
}
//断开连接
closeConnectionAndIgnoreException(pconn);
//判断问题
assertInnerState();
}
/**断开连接*/
private void closeConnectionAndIgnoreException(PooledConnection pconn) {
try {
pconn.close();
} catch (SQLException e) {
log("Error while closing database connection: " + e.toString());
}
}
/**日志输出*/
private void log(String msg) {
String s = "MiniConnectionPoolManager: " + msg;
try {
if (logWriter == null) {
System.err.println(s);
} else {
logWriter.println(s);
}
} catch (Exception e) {
}
}
/**用于判断连接池中的连接数问题*/
private synchronized void assertInnerState() {
if (activeConnections < 0) {
throw new AssertionError();
}
if (activeConnections + recycledConnections.size() > maxConnections) {
throw new AssertionError();
}
if (activeConnections + semaphore.availablePermits() > maxConnections) {
throw new AssertionError();
}
}
/**实现了ConnectionEventListener,注册该对象便可获得由 PooledConnection 对象生成的事件的通知*/
private class PoolConnectionEventListener implements ConnectionEventListener {
//实现其中两个方法
/**当连接关闭的时候,会激活回收相应连接*/
public void connectionClosed(ConnectionEvent event) {
PooledConnection pconn = (PooledConnection) event.getSource();
recycleConnection(pconn);
}
/**当连接发生错误时,断开当前的这个连接*/
public void connectionErrorOccurred(ConnectionEvent event) {
PooledConnection pconn = (PooledConnection) event.getSource();
disposeConnection(pconn);
}
}
/**
* Returns the number of active (open) connections of this pool.
* 返回连接池中处于激活状态的连接
* <p>
* This is the number of <code>Connection</code> objects that have been
* issued by {@link #getConnection()}, for which
* <code>Connection.close()</code> has not yet been called.
*
* @return the number of active connections.
**/
public synchronized int getActiveConnections() {
return activeConnections;
}
/**
* Returns the number of inactive (unused) connections in this pool.
* 返回连接池中没有被激活的连接数目
* <p>
* This is the number of internally kept recycled connections, for which
* <code>Connection.close()</code> has been called and which have not yet
* been reused.
*
* @return the number of inactive connections.
**/
/**返回连接池中没有被激活的连接数目*/
public synchronized int getInactiveConnections() {
return recycledConnections.size();
}
} // end class MiniConnectionPoolManager
针对代码相应的写了注释,相信也就容易看懂了!
但是我自己不理解的其实是那个synchronized这个!!有什么连接讲解的,介绍个资源看看!