数据库连接池DBCP源码剖析

Posted zhumian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库连接池DBCP源码剖析相关的知识,希望对你有一定的参考价值。

BasicDataSource.getConnection()

public Connection getConnection() throws SQLException {
        if (Utils.IS_SECURITY_ENABLED) {
            PrivilegedExceptionAction<Connection> action = new PaGetConnection();
            try {
                return AccessController.doPrivileged(action);
            } catch (PrivilegedActionException e) {
                Throwable cause = e.getCause();
                if (cause instanceof SQLException) {
                    throw (SQLException) cause;
                }
                throw new SQLException(e);
            }
        }
        return createDataSource().getConnection();
    }

createDataSource()

        }

        // Return the pool if we have already created it
        // This is double-checked locking. This is safe since dataSource is
        // volatile and the code is targeted at Java 5 onwards.
        if (dataSource != null) {
            return dataSource;
        }
//同步方法,防止多线程重复创建数据源
synchronized (this) { if (dataSource != null) { return dataSource; } jmxRegister(); // create factory which returns raw physical connections
       //创建JDBC连接工厂
ConnectionFactory driverConnectionFactory = createConnectionFactory(); // Set up the poolable connection factory boolean success = false;
       //创建连接池工厂 PoolableConnectionFactory poolableConnectionFactory;
try { poolableConnectionFactory = createPoolableConnectionFactory( driverConnectionFactory); poolableConnectionFactory.setPoolStatements( poolPreparedStatements); poolableConnectionFactory.setMaxOpenPrepatedStatements( maxOpenPreparedStatements); success = true; } catch (SQLException se) { throw se; } catch (RuntimeException rte) { throw rte; } catch (Exception ex) { throw new SQLException("Error creating connection factory", ex); } if (success) { // create a pool for our connections createConnectionPool(poolableConnectionFactory); } // Create the pooling data source to manage connections DataSource newDataSource; success = false; try { newDataSource = createDataSourceInstance(); newDataSource.setLogWriter(logWriter); success = true; } catch (SQLException se) { throw se; } catch (RuntimeException rte) { throw rte; } catch (Exception ex) { throw new SQLException("Error creating datasource", ex); } finally { if (!success) { closeConnectionPool(); } } // If initialSize > 0, preload the pool
       //往连接池添加初始化大小的连接
try { for (int i = 0 ; i < initialSize ; i++) { connectionPool.addObject(); } } catch (Exception e) { closeConnectionPool(); throw new SQLException("Error preloading the connection pool", e); } // If timeBetweenEvictionRunsMillis > 0, start the pool‘s evictor task startPoolMaintenance(); dataSource = newDataSource; return dataSource; } }

createConnectionFactory():创建连接池工厂

protected ConnectionFactory createConnectionFactory() throws SQLException {
        // Load the JDBC driver class
     //加载数据库驱动
Driver driverToUse = this.driver; if (driverToUse == null) { Class<?> driverFromCCL = null; if (driverClassName != null) { try { try { if (driverClassLoader == null) { driverFromCCL = Class.forName(driverClassName); } else { driverFromCCL = Class.forName( driverClassName, true, driverClassLoader); } } catch (ClassNotFoundException cnfe) { driverFromCCL = Thread.currentThread( ).getContextClassLoader().loadClass( driverClassName); } } catch (Exception t) { String message = "Cannot load JDBC driver class ‘" + driverClassName + "‘"; logWriter.println(message); t.printStackTrace(logWriter); throw new SQLException(message, t); } } try { if (driverFromCCL == null) { driverToUse = DriverManager.getDriver(url); } else { // Usage of DriverManager is not possible, as it does not // respect the ContextClassLoader // N.B. This cast may cause ClassCastException which is handled below driverToUse = (Driver) driverFromCCL.newInstance(); if (!driverToUse.acceptsURL(url)) { throw new SQLException("No suitable driver", "08001"); } } } catch (Exception t) { String message = "Cannot create JDBC driver of class ‘" + (driverClassName != null ? driverClassName : "") + "‘ for connect URL ‘" + url + "‘"; logWriter.println(message); t.printStackTrace(logWriter); throw new SQLException(message, t); } } // Set up the driver connection factory we will use String user = username; if (user != null) { connectionProperties.put("user", user); } else { log("DBCP DataSource configured without a ‘username‘"); } String pwd = password; if (pwd != null) { connectionProperties.put("password", pwd); } else { log("DBCP DataSource configured without a ‘password‘"); }      //创建JDBC连接工厂 ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driverToUse, url, connectionProperties); return driverConnectionFactory; }

createPoolableConnectionFactory()

protected PoolableConnectionFactory createPoolableConnectionFactory(
            ConnectionFactory driverConnectionFactory) throws SQLException {
        PoolableConnectionFactory connectionFactory = null;
        try {
            connectionFactory = new PoolableConnectionFactory(driverConnectionFactory, registeredJmxName);
            connectionFactory.setValidationQuery(validationQuery);
            connectionFactory.setValidationQueryTimeout(validationQueryTimeout);
            connectionFactory.setConnectionInitSql(connectionInitSqls);
            connectionFactory.setDefaultReadOnly(defaultReadOnly);
            connectionFactory.setDefaultAutoCommit(defaultAutoCommit);
            connectionFactory.setDefaultTransactionIsolation(defaultTransactionIsolation);
            connectionFactory.setDefaultCatalog(defaultCatalog);
            connectionFactory.setCacheState(cacheState);
            connectionFactory.setPoolStatements(poolPreparedStatements);
            connectionFactory.setMaxOpenPrepatedStatements(maxOpenPreparedStatements);
            connectionFactory.setMaxConnLifetimeMillis(maxConnLifetimeMillis);
            connectionFactory.setRollbackOnReturn(getRollbackOnReturn());
            connectionFactory.setEnableAutoCommitOnReturn(getEnableAutoCommitOnReturn());
            connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeout());
            connectionFactory.setFastFailValidation(fastFailValidation);
            connectionFactory.setDisconnectionSqlCodes(disconnectionSqlCodes);
            validateConnectionFactory(connectionFactory);
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new SQLException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
        }
        return connectionFactory;
    }

createConnectionPool():创建对象池保存活跃连接

protected void createConnectionPool(PoolableConnectionFactory factory) {
        // Create an object pool to contain our active connections
        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        updateJmxName(config);
        config.setJmxEnabled(registeredJmxName != null);  // Disable JMX on the underlying pool if the DS is not registered.
        GenericObjectPool<PoolableConnection> gop;
        if (abandonedConfig != null &&
                (abandonedConfig.getRemoveAbandonedOnBorrow() ||
                 abandonedConfig.getRemoveAbandonedOnMaintenance())) {
            gop = new GenericObjectPool<>(factory, config, abandonedConfig);
        }
        else {
            gop = new GenericObjectPool<>(factory, config);
        }
        gop.setMaxTotal(maxTotal);
        gop.setMaxIdle(maxIdle);
        gop.setMinIdle(minIdle);
        gop.setMaxWaitMillis(maxWaitMillis);
        gop.setTestOnCreate(testOnCreate);
        gop.setTestOnBorrow(testOnBorrow);
        gop.setTestOnReturn(testOnReturn);
        gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
        gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        gop.setTestWhileIdle(testWhileIdle);
        gop.setLifo(lifo);
        gop.setSwallowedExceptionListener(new SwallowedExceptionLogger(log, logExpiredConnections));
        gop.setEvictionPolicyClassName(evictionPolicyClassName);
        factory.setPool(gop);
     //生成对象池 connectionPool
= gop; }

 

从图中可以看出,由执行器Executor获取数据库连接进行数据库操作的

技术分享图片

PoolableConnection.getConnection()

public Connection getConnection() throws SQLException {
        try {
       //从连接池获取连接 C conn
= _pool.borrowObject(); if (conn == null) { return null; } return new PoolGuardConnectionWrapper<>(conn); } catch(SQLException e) { throw e; } catch(NoSuchElementException e) { throw new SQLException("Cannot get a connection, pool error " + e.getMessage(), e); } catch(RuntimeException e) { throw e; } catch(Exception e) { throw new SQLException("Cannot get a connection, general error", e); } }

PoolableConnection.close():这里的关闭连接只是把对象返回到连接池中,并非是真正的关闭

public synchronized void close() throws SQLException {
        if (isClosedInternal()) {
            // already closed
            return;
        }

        boolean isUnderlyingConectionClosed;
        try {
            isUnderlyingConectionClosed = getDelegateInternal().isClosed();
        } catch (SQLException e) {
            try {
                _pool.invalidateObject(this);
            } catch(IllegalStateException ise) {
                // pool is closed, so close the connection
                passivate();
                getInnermostDelegate().close();
            } catch (Exception ie) {
                // DO NOTHING the original exception will be rethrown
            }
            throw new SQLException("Cannot close connection (isClosed check failed)", e);
        }

        /* Can‘t set close before this code block since the connection needs to
         * be open when validation runs. Can‘t set close after this code block
         * since by then the connection will have been returned to the pool and
         * may have been borrowed by another thread. Therefore, the close flag
         * is set in passivate().
         */
        if (isUnderlyingConectionClosed) {
            // Abnormal close: underlying connection closed unexpectedly, so we
            // must destroy this proxy
            try {
                _pool.invalidateObject(this);
            } catch(IllegalStateException e) {
                // pool is closed, so close the connection
                passivate();
                getInnermostDelegate().close();
            } catch (Exception e) {
                throw new SQLException("Cannot close connection (invalidating pooled object failed)", e);
            }
        } else {
            // Normal close: underlying connection is still open, so we
            // simply need to return this proxy to the pool
            try {
          //将连接返回到连接池中 _pool.returnObject(
this); } catch(IllegalStateException e) { // pool is closed, so close the connection passivate(); getInnermostDelegate().close(); } catch(SQLException e) { throw e; } catch(RuntimeException e) { throw e; } catch(Exception e) { throw new SQLException("Cannot close connection (return to pool failed)", e); } } }

 













以上是关于数据库连接池DBCP源码剖析的主要内容,如果未能解决你的问题,请参考以下文章

MySQL与Redis数据库连接池介绍(图示+源码+代码演示)

c3p0,dbcp与druid 三大连接池的区别[转]

数据库连接池DBCP的使用

DBCP数据库连接池的简单使用

DBCP数据库连接池的简单使用

Java学习:数据库连接池DBCP的使用