|
最近跟随Tomcat7.0开发了一个JDBC 连接池。
Svn: http://svn.apache.org/repos/asf/tomcat/trunk/modules/jdbc-pool
http://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html上大篇幅的介绍,包括基本的使用指南。本篇从源码的角度,分析该连接池的实现思路。
应用使用JDBC连接也,主要关注以下三个方面:
1. 获取连接
2. 归还连接
3.空闲连接关闭。
一. 获取连接
ConnectionPool提供三个接口用于获取连接:
- public Future getConnectionAsync() throws SQLException {
-
- try {
-
- PooledConnection pc = borrowConnection(0, null, null);
-
- if (pc!=null) {
-
- return new ConnectionFuture(pc);
-
- }
-
- }catch (SQLException x) {
-
- if (x.getMessage().indexOf("NoWait")) {
-
- Future pcf = ((MultiLockFairBlockingQueue)idle).pollAsync();
-
- return new ConnectionFuture(pcf);
-
- } else {
-
- throw new SQLException("Connection pool is misconfigured, doesn't support async retrieval. Set the 'fair' property to 'true'");
-
- }
-
-
-
- public Connection getConnection() throws SQLException {
-
- //check out a connection
-
- PooledConnection con = borrowConnection(-1,null,null);
-
- return setupConnection(con);
-
- }
-
- public Connection getConnection(String username, String password) throws SQLException {
-
- // check out a connection
-
- PooledConnection con = borrowConnection(-1, username, password);
-
- return setupConnection(con);
-
- }
第一个方法:getConnectionAsync用于获取一个连接的Feature.它用于支持以异步的方式获取连接。后两个方法不同之处就是传递了所需连接的用户名与密码。我们这里得点分析第三个方法.
PooledConnection con = borrowConnection(-1, username, password);
borrowConnection方法从空闲队列中获取一个连接,或新建一个连接。看一下源码:
- /**
-
- * Thread safe way to retrieve a connection from the pool
-
- * @param wait - time to wait, overrides the maxWait from the properties,
-
- * set to -1 if you wish to use maxWait, 0 if you wish no wait time.
-
- * @return PooledConnection
-
- * @throws SQLException
-
- */
-
- private PooledConnection borrowConnection(int wait, String username, String password) throws SQLException {
-
- //如果连接被关闭则直接抛出异常
-
- if (isClosed()) {
-
- throw new SQLException("Connection pool closed.");
-
- } //end if
-
-
-
- //get the current time stamp
-
- long now = System.currentTimeMillis();
-
- //see if there is one available immediately
-
- /*从空闲队列中获取一个连接。 其实idle里存在连接对象有的可能并没有
-
- 绑定物理连接。这也是Tomcat jdbc pool的一个特别,连接在将要被使用时,
-
- 才会初始化*/
-
- PooledConnection con = idle.poll();
-
- while (true) {
-
- if (con!=null) {
-
- //configure the connection and return it
-
- /*这里又出现一个borrowConnection的重载方法。该方法对从空闲队列中取到的连接对象进行配置和验证,稍后评述*/
-
- PooledConnection result = borrowConnection(now, con, username, password);
-
- //null should never be returned, but was in a previous impl.
-
- // null should never be returned这句注释不对,根据后面的代码
-
- // 来看,null是有可能发生。
-
- if (result!=null) return result;
-
- }
-
- //if we get here, see if we need to create one
-
- //this is not 100% accurate since it doesn't use a shared
-
- //atomic variable - a connection can become idle while we are creating
-
- //a new connection
-
- /*从上面的英文注释我们很明白,当执行到这里时,唯一的可能是idle队列没能取到连接对象。
- 如果条件允许,我们将创建新的连接.在这里作者用了一个特别的算法,也是tomcat代码中常用的,
- 我们姑且称他占位法(我一般这么叫)。这个算法的特点就是先在计数器Size中占一个位置
- (Size是原子变量。能够解决并发问题)。即size+1.然后检查size有没有超标。如果超标
- 则减去刚才新加的1。否则创建一个新的连接。不过这里我注意的是,如果创建新连接时失败,
- size也必须减1。其实与大学时的用书抢位子异曲同工。*/
-
- if (size.get() < getPoolProperties().getMaxActive()) {
-
- //atomic duplicate check
-
- if (size.addAndGet(1) > getPoolProperties().getMaxActive()) {
-
- //if we got here, two threads passed through the first if
-
- size.decrementAndGet();
-
- } else {
-
- //create a connection, we're below the limit
-
- //后面再描述这个方法。
-
- return createConnection(now, con, username, password);
-
- }
-
- } //end if
-
- //到这里则表示连接池已满,不能创建新的连接,我们只能等待其他线程释放的连接
-
- //calculate wait time for this iteration
-
- long maxWait = wait;
-
- //if the passed in wait time is -1,
-
- //means we should use the pool property value
-
- if (wait==-1) {
-
- maxWait = (getPoolProperties().getMaxWait()
|
|
|