1. 程式人生 > >數據庫連接池DBCP源碼剖析

數據庫連接池DBCP源碼剖析

for targe evict 執行 disco 成對 加載數據 swa 行數據

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源碼剖析