dbcp中几个重要实现类之间的关系和链接池参数简介

  以下图1所示主要分析的是BasicDataSourceGenericObjectPoolDriverConnectionFactoryPoolableConnectionFactoryPoolingDataSource类。java

1  dbcp几个重要实现类的关系算法

   咱们直接使用的最多的就是BasicDataSource类了,这个类主要是设置一些数据库链接池的参数,不过这些参数基本都是经过GenericObjectPool的实例来实现的。数据库

   在BasicDataSource中最重要的方法就是createDataSource方法了,这个方法中回建立一个GenericObjectPool实例来管理数据库链接(AbandonedObjectPool类已经不被推荐了,因此这里不考虑),最后这个方法返回的是PoolingDataSource的实例,这个类主要是对GenericObjectPool和数据库链接的一些代理实现。下面是createDataSource方法的实现。测试

protected synchronized DataSource createDataSource()
            throws SQLException {

            // 若是已经建立了DataSource则直接返回
            if (dataSource != null) {
                return (dataSource);
            }

            // 加载 数据库驱动类
            if (driverClassName != null) {
                try {
                    Class.forName(driverClassName);
                } catch (Throwable t) {
                    String message = "Cannot load JDBC driver class '" +
                        driverClassName + "'";
                    logWriter.println(message);
                    t.printStackTrace(logWriter);
                    throw new SQLNestedException(message, t);
                }
            }

            // 获得一个数据库驱动的实例 
            Driver driver = null;
            try {
                driver = DriverManager.getDriver(url);
            } catch (Throwable t) {
                String message = "Cannot create JDBC driver of class '" +
                    (driverClassName != null ? driverClassName : "") + 
                    "' for connect URL '" + url + "'";
                logWriter.println(message);
                t.printStackTrace(logWriter);
                throw new SQLNestedException(message, t);
            }

            // 若是没有配置(设置)validationQuery参数,则不执行相应的测试
            //下面的3个方法都是测试连接是否有效的
            //setTestOnBorrow方法是在得到链接的时候测试连接时候有效
            //setTestOnReturn是在数据库链接池使用完链接把它放入空闲链表中的时候测试链接是否有效
            //setTestWhileIdle是在驱逐超时的空闲链接的时候测试连接是否有效
            if (validationQuery == null) {
                setTestOnBorrow(false);
                setTestOnReturn(false);
                setTestWhileIdle(false);
            }

            // 若是配置了abandonedConfig 相应的参数则使用AbandonedObjectPool,则是是不推荐的
            if ((abandonedConfig != null) && (abandonedConfig.getRemoveAbandoned())) {
                connectionPool = new AbandonedObjectPool(null,abandonedConfig);
            }
            //因此通常使用的是GenericObjectPool类,这个类的主要工做是管理数据库链接池相关的配置
            //例如获取数据库链接,保证数据库链接池中的的空闲连接,驱逐空闲链接,
            //就是和数据库链接池相关的配置都由它管理实现,它为不少配置提供了默认值
            else {
                connectionPool = new GenericObjectPool();
            }
            connectionPool.setMaxActive(maxActive);
            connectionPool.setMaxIdle(maxIdle);
            connectionPool.setMinIdle(minIdle);
            connectionPool.setMaxWait(maxWait);
            connectionPool.setTestOnBorrow(testOnBorrow);
            connectionPool.setTestOnReturn(testOnReturn);
            connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
            connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
            connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
            connectionPool.setTestWhileIdle(testWhileIdle);
            
            
            GenericKeyedObjectPoolFactory statementPoolFactory = null;
            if (isPoolPreparedStatements()) {
                statementPoolFactory = new GenericKeyedObjectPoolFactory(null, 
                            -1, // unlimited maxActive (per key)
                            GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL, 
                            0, // maxWait
                            1, // maxIdle (per key) 
                            maxOpenPreparedStatements); 
            }

            
            if (username != null) {
                connectionProperties.put("user", username);
            } else {
                log("DBCP DataSource configured without a 'username'");
            }
            
            if (password != null) {
                connectionProperties.put("password", password);
            } else {
                log("DBCP DataSource configured without a 'password'");
            }
            
            //这个是实际得到数据库链接的工厂类
            DriverConnectionFactory driverConnectionFactory =
                new DriverConnectionFactory(driver, url, connectionProperties);

            // 这个类实现了PoolableObjectFactory,它作的是封装一个DriverConnectionFactory
            //来获得实际的链接,封装了一个GenericObjectPool来管理链接池,固然都是针对接口的
            //重要的一点就是它把自身传递到了GenericObjectPool中,这样就只须要暴露GenericObjectPool
            PoolableConnectionFactory connectionFactory = null;
            try {
                connectionFactory =
                    new PoolableConnectionFactory(driverConnectionFactory,
                                                  connectionPool,
                                                  statementPoolFactory,
                                                  validationQuery,
                                                  defaultReadOnly,
                                                  defaultAutoCommit,
                                                  defaultTransactionIsolation,
                                                  defaultCatalog,
                                                  abandonedConfig);
                if (connectionFactory == null) {
                    throw new SQLException("Cannot create PoolableConnectionFactory");
                }
                validateConnectionFactory(connectionFactory);
            } catch (RuntimeException e) {
                throw e;
            } catch (Exception e) {
                throw new SQLNestedException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
            }

            // Create and return the pooling data source to manage the connections
            dataSource = new PoolingDataSource(connectionPool);
            ((PoolingDataSource) dataSource).setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
            dataSource.setLogWriter(logWriter);
            
            try {
                for (int i = 0 ; i < initialSize ; i++) {
                    connectionPool.addObject();
                }
            } catch (Exception e) {
                throw new SQLNestedException("Error preloading the connection pool", e);
            }
            
            return dataSource;
        }

 

      GenericObjectPool类主要是管理数据库链接池的,它主要实现了对数据库链接池参数的管理,例如链接池的最大数,它的建立链接时经过PoolableConnectionFactory的实例来实现的,不过它作了代理在建立链接的时候先检查了数据库的活动链接是否是已经达到了最大值,若是没有就继续建立,若是达到了参数设置的最大值就按指定的策略执行,默认的策略是当数据库链接池中的链接达到的最大值是在建立链接就会被阻塞(wait),这就是在上一篇中程序被挂起的主要缘由。GenericObjectPool还能够检查最小的空闲链接,最大的空闲链接,驱逐超时的空闲链接。下面将数据库链接池参数的时候再介绍。url

    DriverConnectionFactory是实际获取数据库链接的类,它调用的是底层的数据库驱动。spa

     PoolableConnectionFactory主要实现了建立链接,关闭链接,验证链接,使链接钝化(关闭Statement,设置关闭标志,不是真的关闭),激活链接等操做。GenericObjectPool关于链接的操做基本就是经过它实现的。.net

2 dbcp数据库链接池参数线程

   如上图2所示是dbcp数据库链接池的一些重要的参数,除了重要部分所示的usernamepasswordurldriverClassName参数使用BasicDataSource直接管理,其余基本都是经过GenericObjectPool来管理的。代理

   这里只是介绍一些比较容易混淆,不易理解的参数。首先看基本的initialSize是表示数据库链接池初始化的时候建立多少个链接。maxTotal是数据库链接池中最多建立多少个链接,maxIdelminIdel是指最大空闲链接和最小空闲链接的数量,空闲链接是指使用事后的链接关闭链接(并无真正关闭链接,而是加入了GenericObjectPool空闲链接列表的数量(假设使用的是GenericObjectPool))。maxWaitMills参数是指当数据库链接池中的链接达到最大值的时候,被阻塞等待的时间(wait(maxWaitMills)),超时就会抛出异常。code

   验证链接有效性的4个参数:首先必须得设置validationQuery参数,这个参数就是验证链接有效性的SQL语句,能够设置为select 1 from dual。只有设置了这个参数其余的三个参数才会生效。这个从createDataSource方法的代码中能够轻易的看出来。testOnBorrow是指在获取链接的时候检查链接的有效性,testOnReturn是指在关闭链接(不是真正关闭,而是加入到空闲链接列表的时候)验证链接的有效性。testOnIdle是指在驱逐空闲链接的时候验证链接的有效性。

   驱逐链接相关的3个参数,timeBetweenEvictionRunsMills参数是值多长时间执行一次驱逐算法minEvictableIdleMills参数是指空闲链接的超时时间(就是这个链接有多久没有用就能够被回收了)numTestsPerEvictionRun参数是值设置几个线程来执行驱逐算法。这个算法其实不是特别复杂,只是有一个Timer计时器,在构造的时候启动Evictor,其中Evictor实现了TimerTask。调用了GenericObjectPool public synchronized void evict() throws Exception方法。由于每个链接在建立的时候又一个时间戳,对比一下就能够了。

   至于自动回收泄露链接的那几个参数,由于类已经不被推荐了因此也没有仔细看,就不介绍了。

记一次dbcp数据库链接池问题分析

相关文章
相关标签/搜索