数据库程序接口——JDBC——功能第二篇——数据源之C3P0数据源

2023-05-24,,

综述

C3P0由三部分内容组成。实例化对象,各配置项的含义,以及加载配置项的方式。

实例化对象的方式有三种,第一种方式直接new ComboPooledDataSource,第二种方式使用工厂类DataSources.poolDataSource方法。第三种不常见。第一种方式是最方便的方式。

C3P0的配置项主要有:

    连接数据库的必要属性:例如jdbcUrl,user,password等。
    连接池的大小配置。例如initialPoolSize
    连接对象的生命周期。例如maxConnectionAge。
    测试连接的配置,例如preferredTestQuery指定测试SQL语句。
    重连策略的配置,例如acquireRetryAttempts指定重连次数。
    statement对象的配置,例如maxStatements指定最大Statement的总数。
    线程配置,例如numHelperThread指定连接池拥有的线程数量。
    事务配置,例如autoCommitOnClose指定是否在回收连接对象时自动提交事务。
    调试模式,例如debugUnreturnedConnectionStackTraces为true时,会打印所有从连接池获取连接对象的记录。
    监听类的设置,例如connectionCustomizerClassName指定监听类的名称,该类可以实现onAcquire,onDestory等方法。
    日志的设置,例如com.mchange.v2.log.MLog指定日志的实现方式。常见的有log4J,commonLogging等。

配置项常见的加载方式有三种:

    代码方式:通过实例对象调用setXX方法。
    properties文件:这种方式需要properties文件的名称必须为c3p0.properties,而且该文件必须在类加载路径下。
    xml文件:这种方式需要文件名称为c3p0-config.xml,路径由com.mchange.v2.c3p0.cfg.xml指定。

实例化

实例化ComboPooledDataSource

 // 创建实例,dataSourceName指定数据源的名称
ComboPooledDataSource dataSource = new ComboPooledDataSource(dataSourceName);
// 设置数据库url
dataSource.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:masteroracle");
// 设置数据库驱动类
dataSource.setDriverClass("oracle.jdbc.driver.OracleDriver");
// 设置用户名
dataSource.setUser("system");
// 设置密码
dataSource.setPassword("password");
Connection conn = dataSource.getConnection();
runSQLTest(conn);

工厂DataSources方式

 // 创建unpooled的数据源
DataSource ds_unpooled = DataSources.unpooledDataSource(jdbcUrl, user, password);
// pooled数据源的参数
Map<String,String> paramMap = new HashMap<>();
DataSource pooled = DataSources.pooledDataSource(ds_unpooled,paramMap);
Connection conn = pooled.getConnection();
runSQLTest(conn);
conn.close();
DataSources.destroy(pooled);
return pooled;

配置项的含义

C3P0各配置项的前缀为c3p0。如果指定dataSourceName,前缀为c3p0.named-configs.dataSourceName。如果存在多个用户,用户可以覆盖默认的配置项,前缀为c3p0.user-overrides.user。

Java代码方式

     /** -----------------------配置数据源----------------------------- **/
/**
* 配置数据源
*
* @param dataSource
* @return
* @throws PropertyVetoException
*/
public static ComboPooledDataSource configDataSource(ComboPooledDataSource dataSource)
throws PropertyVetoException {
// 连接数据库的必要属性
connDatabaseConfig(dataSource,"masterOracle");
// 连接池的相关配置
connPoolConfig(dataSource);
// 连接对象的生命周期配置
connAgeConfig(dataSource);
// 测试连接的配置
connTestConfig(dataSource);
// statement对象的配置
statementConfig(dataSource);
// 重连配置
reconnConfig(dataSource);
// 连接的监听类配置
connListenerConfig(dataSource);
// 事务的配置
tranConfig(dataSource);
// 调试模式
debugMode(dataSource);
// 线程配置
threadConfig(dataSource);
return dataSource;

连接必要属性

    driverClassName:驱动类的名称,包名+类名
    jdbcUrl:数据库实例的url地址,格式为jdbc:subprotocol:subname。其中subprotocol表示连接方式。
    user:用户名
    password:密码。

C3P0.properties的方式

##-------------------------------数据库连接属性-----------------------------------##
# 驱动类名称
c3p0.driverClass=oracle.jdbc.driver.OracleDriver
# 数据库实例url地址
c3p0.jdbcUrl=jdbc:oracle:thin:@localhost:1521:masteroracle
# 用户名
c3p0.user=system
# 密码
c3p0.password=password

代码方式

         // 设置数据库url
dataSource.setJdbcUrl(jdbcUrl);
// 设置数据库驱动类
dataSource.setDriverClass(driverClassName);
// 设置用户名
dataSource.setUser(user);
// 设置密码
dataSource.setPassword(password);
// 输出dataSourceName,在初始化ComboPooledDataSource时,字符串参数作为数据源名称,
dataSource.getDataSourceName();

连接池大小

    initialPoolSize:连接池的初始需求量大小,实际创建的连接对象小于需求量大小。
    minPoolSize:连接池连接数量的最小值。
    maxPoolSize:连接池连接数量的最大值。
    acquireIncrement:当实际连接不够用时,调整需求量的大小,需求量的递增值。

C3P0.properties的方式

##-------------------------------连接池配置-------------------------------------##
# 连接池拥有连接对象的初始值,这种情形下只是Acquire(需求)的初始值,真正创建对象会根据Acquire来按需创建
c3p0.initialPoolSize=10
# 连接池拥有连接对象的最大值,默认值为3
c3p0.maxPoolSize=20
# 连接池拥有连接对象的最小值,默认值为3
c3p0.minPoolSize=5
# 当无空闲连接时,新创建的连接数,默认值为3
c3p0.acquireIncrement=3

代码方式

     /**
* 连接池的配置 initialPoolSize:连接池的初始值 maxPoolSize:连接池的最大值 minPoolSize:连接池的最小值
*
* @param dataSource
*/
private static void connPoolConfig(ComboPooledDataSource dataSource) {
// 连接池的初始值,默认值为3
dataSource.setInitialPoolSize(10);
// 连接池的最大值,默认值为0
dataSource.setMaxPoolSize(20);
// 连接池的最小值,最小值为3
dataSource.setMinPoolSize(1);
// 连接池的递增值,默认值为3
dataSource.setAcquireIncrement(5);
}

连接生命周期

    maxIdleTime:空闲连接对象的超时时间,当连接对象处于空闲状态的时间超过此时间,连接池销毁该连接对象。
    maxConnectionAge:连接对象的最大生命值,从创建连接对象开始计算。当超出此时间,销毁连接对象。与maxIdleTime的区别在于maxIdleTime只适用于空闲连接对象,而且是从空闲状态开始计算时间。
    maxIdleTimeExcessConnections:当连接池负载较低时,空闲连接对象的超时时间,设置此项可以在负载较低时,快速的释放链接。
    unreturnedConnectionTimeout:连接对象的最大使用时间。从连接池中获取连接对象开始计算,如果超出此时间,该连接对象还没有被连接池回收,那么连接池创建新连接对象替换旧连接对象。

C3P0.proerties的方式

##-------------------------------连接池中连接对象的生命周期--------------------------##
# 连接对象的最大生存时间,起始时间从连接池从数据库中创建连接对象开始计算。0表示永远不销毁
c3p0.maxConnectionAge=0
# 空闲连接对象的超时时间,起始时间从连接对象状态变为空闲时起计算。
c3p0.maxIdleTime=1800
# 当连接池不处于满载状态时,空闲连接对象的最大生存时间,设置此值,可以快速的减少连接池的大小
c3p0.maxIdleTimeExcessConnections=60
# 连接对象回收的超时时间,当连接池无法在一定时间内回收连接对象时,销毁旧对象,重新创建新对象
c3p0.unreturnedConnectionTimeout=600

代码方式

    /**
* 连接池生命周期配置,连接池首先从数据库中获取连接,用户请求时从连接池中获取连接。默认值为0,表示永不过期。 maxConnectionAge:
* 连接对象生命的最大值,超过此时间,连接池会销毁连接对象,连接池变小。单位为秒,建议设置1800或更多 maxIdleTime:
* 空闲连接在连接池中的超时时间,超过此时间,连接池将会销毁连接对象。单位为秒,建议设置1800或更多
* maxIdleTimeExcessConnections:当连接池不处于过载状态时,空闲连接对象生命的最大值。
* unreturnedConnectionTimeout:当连接对象在一定时间内无法回收,则创建新连接对象,销毁旧连接对象
*
* @param dataSource
*/
private static void connAgeConfig(ComboPooledDataSource dataSource) {
// 连接对象生命的最大值,它指绝对时间。从创建开始时计算,默认值为0
dataSource.setMaxConnectionAge(10 * 60 * 60);
// 空闲连接的超时时间,从连接池变为空闲状态开始计算
dataSource.setMaxIdleTime(1800);
// 空闲连接对象生命的最大值
dataSource.setMaxIdleTimeExcessConnections(60);
// 连接对象的最大使用时间,设置为2小时
dataSource.setUnreturnedConnectionTimeout(2 * 60 * 60);
}

测试连接

    automaticTestTable:测试连接使用的数据库表
    connectionTesterClassName:测试连接使用的类名称
    idleConnectionTestPeriod:测试连接的时间间隔,在此间隔内不执行连接测试
    preferredTestQuery:SELECT 1。如果支持JDBC 4,会使用Connection.isAlive方法不设置此值。
    testConnectionOnCheckin:是否在连接池中回收连接对象时进行连接测试,
    testConnectionOnCheckOut:从连接池中取出连接对象时进行连接测试。

C3P0.properties的方式

##-------------------------------测试连接配置项----------------------------------##
# 从连接池中获取连接对象时进行连接测试
c3p0.testConnectionOnCheckout=true
# 从连接池回收对象时进行连接测试
c3p0.testConnectionOnCheckin=true
# 连接测试的间隔,在这一段时间内不进行连接测试
c3p0.idleConnectionTestPeriod=60
# 连接测试时使用的类,设置此值时忽略preferredTestQuery,automaticTestTable等属性值
#c3p0.connectionTesterClassName=com.rain.Tester.ConnectionTesterSample
# 测试的SQL语句
c3p0.preferredTestQuery=select 1
# 连接测试时使用的数据库表
c3p0.automaticTestTable=test

代码方式

    /**
* 连接测试配置。 automaticTestTable:测试连接时使用的数据库表 ,默认值为null。connectionTesterClassName:测试连接时使用的类名称
* idleConnectionTestPeriod:测试连接间隔时间。在此段时间内不进行连接测试。 preferredTestQuery:连接测试使用的SQL语句。默认语句为select
* 1 from dual。 testConnectionOnCheckin:从连接池回收连接对象时测试连接。默认值为false
* testConnectionOnCheckOut:从连接池取出连接对象时测试连接。默认值为false。
* forceSynchronousCheckins:连接池回收连接对象时是同步,还是异步,默认是异步。默认值为false
*
* @param dataSource
* @throws PropertyVetoException
*/
private static void connTestConfig(ComboPooledDataSource dataSource)
throws PropertyVetoException {
// 连接测试使用的数据库表,默认值为Null
dataSource.setAutomaticTestTable("dual");
// 连接测试使用的SQL语句,默认使用Connection对象的isAlive方法,所以一般不设置此值,默认值为null
dataSource.setPreferredTestQuery("select 1");
// 从连接池取出连接时测试连接,默认值为false
dataSource.setTestConnectionOnCheckout(true);
// 从连接池回收连接时测试连接,默认值为false。
dataSource.setTestConnectionOnCheckin(true);
// 测试连接的间隔时间,默认值为0
dataSource.setIdleConnectionTestPeriod(60);
// 测试连接使用的类名称
dataSource.setConnectionTesterClassName("com.rain.Tester.ConnectionTesterSample");
}

重连策略

    acquireRetryAttempts:连接失败后,重连次数
    acquireRetryDelay:第一次重连与第二次重连的时间间隔。单位为毫秒
    checkTimeOut:等待连接的超时时间,超出此时间后不在进行重连。
    breakAfterAcquireFailure:当连接失败后,是否销毁数据源对象,true表示是,false表示否。

C3P0.properties

##-------------------------------重新连接---------------------------------------##
# 重新连接的次数
c3p0.acquireRetryAttempts=5
# 重新连接的时间间隔,单位为毫秒
c3p0.acquireRetryDelay=3000
# 等待连接响应的超时时间
c3p0.checkoutTimeout=120
# 当连接失败时,是否销毁数据源对象,true表示是,false表示否
c3p0.breakAfterAcquireFailure=true

代码方式

    /**
* 当连接失败后,重新连接的配置。 acquireRetryAttempts:重连的次数。 acquireRetryDelay:重连的时间间隔。单位为毫秒
* breakAfterAcquireFailure:重连失败后,如果此值设置为false,数据源对象不会销毁,设置为false。数据源被销毁。
* checkoutTimeout:等待连接响应的时间。
*/
private static void reconnConfig(ComboPooledDataSource dataSource) {
// 设置重连次数为3,默认值为30
dataSource.setAcquireRetryAttempts(3);
// 设置重连的时间间隔为2秒,默认值为1000
dataSource.setAcquireRetryDelay(2000);
// 等待连接响应的超时时间。默认值为0表示永远不超时
dataSource.setCheckoutTimeout(4);
// 重连失败后,销毁数据源。默认值为false
dataSource.setBreakAfterAcquireFailure(true);
}

Statement配置

    maxStatements:连接池缓存PreparedStatement对象的总数
    maxStatementsPerConnection:每个连接缓存PreparedStatement的最大值。
    statementCacheNumDeferredCloseThreads:当Connection关闭时,有可能会产生Statement对象没有关闭的情形,此时需要额外线程确保Statement对象在Connection关闭时正在关闭。一般配置为0或1

C3P0.properties的方式

##-------------------------------statement对象相关配置---------------------------##
# c3p0拥有的PreparedStatement对象的总数
c3p0.maxStatements=100
# 每个连接拥有PreparedStament对象的数量
c3p0.maxStatementsPerConnection=10
# 当Connection对象关闭时,启动额外线程确保statement对象关闭
# This parameter should only be set if you observe that attempts by c3p0 to close() cached #statements freeze
statementCacheNumDeferredCloseThreads=1

代码方式

     /**
* 连接池中PreparedStatement对象的配置 PreparedStatement对象的配置。 maxStatements:连接池拥有PreparedStatement对象的总数。
* maxStatementsPerConnections:每个连接拥有PreparedStatement对象的数目。
*
* @param dataSource
*/
private static void statementConfig(ComboPooledDataSource dataSource) {
// 设置PreparedStatement对象的总数,默认值为0,表示关闭
dataSource.setMaxStatements(100);
// 设置每个连接拥有Statement对象的数目,默认值为0,表示关闭。
dataSource.setMaxStatementsPerConnection(15);
}

线程配置

    numHelperThreads:连接池拥有的线程数量。
    maxAdministrativeTaskTime:线程执行任务的超时时间,当超出此时间时,会销毁该线程,重新创建新线程。
    forceSynchronousCheckins:连接池回收连接对象时默认是同步方式执行连接测试,此值设置为true时,连接测试与回收连接对象是异步执行的。

C3P0.properties的方式

##-------------------------------线程池----------------------------------------##
# 连接池拥有的线程数量
c3p0.numHelperThreads=5
# 线程执行的最大时间
c3p0.maxAdministrativeTaskTime=600
# 启动独立的线程来在连接被连接池回收阶段进行测试
forceSynchronousCheckins=true

代码方式

     /**
* 连接池的线程设置 numHelperThread:连接池拥有的线程数量 maxAdministrativeTaskTime:线程执行的超时时间。
*
* @param dataSource
*/
private static void threadConfig(ComboPooledDataSource dataSource) {
// 设置线程数量为10,默认值为3
dataSource.setNumHelperThreads(10);
// 设置线程的超时时间,默认值为0,设置为5分钟
dataSource.setMaxAdministrativeTaskTime(5 * 60);
}

事务配置

    autoCommitOnClose:回收连接对象时,是否自动提交事务。默认不配置,通过其他方式管理事务,例如Spring事务
    forceIgnoreUnresolvedTransactions:回收连接对象时,是否强制回滚或者提交事务,默认不配置。

C3P0.properties的方式

##-------------------------------事务-----------------------------------------##
# 交给Spring去管理事务,默认不配置这些项
# 连接关闭时,是否自动提交事务
c3p0.autoCommitOnClose=false
# 连接回收时,是否强制提交或者回滚当前连接拥有的事务,默认不配置。
c3p0.forceIgnoreUnresolvedTransactions=false

代码方式

     /**
* 连接对象的事务配置 autoCommitOnClose:是否自动提交事务,true为是,false为否,默认为否 forceIgnoreUnresolvedTransactions
* 回收连接时,是否强制回滚或提交事务,默认为false。一般不设置此值, 例如由Spring来管理事务
*
* @param dataSource
*/
private static void tranConfig(ComboPooledDataSource dataSource) {
// 关闭自动提交事务,默认值为false
dataSource.setAutoCommitOnClose(false);
// 回收连接时,是否强制回滚或提交事务,设置为false。
dataSource.setForceIgnoreUnresolvedTransactions(false); }

调试模式

    debugUnreturnedConnectionStackTraces:打印从连接池获取连接对象的所有信息。

C3P0.properties的方式

##-------------------------------调试模式--------------------------------------##
# 当从连接池获取连接对象时,打印所有信息。
c3p0.debugUnreturnedConnectionStackTraces=true

代码方式

     /**
* 调试模式的设置 debugUnreturnedConnectionStackTraces:从连接池获取连接对象时,打印所有信息 *
* @param dataSource
*/
private static void debugMode(ComboPooledDataSource dataSource) {
// 从连接池获取连接对象时,打印所有信息
dataSource.setDebugUnreturnedConnectionStackTraces(true);
}

监听类

connectionCustomizerClassName:监听类的名称,监听类继承自AbstractConnectionCustomizer,监听类有四个方法

    onAcquire在数据库中创建连接对象时触发。
    onDestory在连接池中销毁连接对象时触发。
    onCheckOut从连接池获取连接对象时触发
    onCheckIn 从连接池回收连接对象时触发。

C3P0.properties的方式

##-------------------------------监听类---------------------------------------##
c3p0.connectionCustomizerClassName=com.rain.Tester.ConnCustomrizerSample

代码方式

     /**
* 设置连接对象的监听类,该类有四个方法 onAcquire:表示当连接池从数据库中获得连接时 onDestory:表示当连接池销毁连接对象时 onCheckOut:从连接池中获取连接对象时
* onCheckIn:连接池回收连接对象时。
*/
private static void connListenerConfig(ComboPooledDataSource dataSource) {
// 设置连接对象的监听类
dataSource.setConnectionCustomizerClassName("com.rain.Tester.ConnCustomrizerSample");
}

日志配置

    com.mchange.v2.log.MLog:日志的实现方式
    com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL:日志的级别。可选值为OFF,SERVER,WARNING,INFO,FINE,FINER,FINEST,ALL
    com.mchange.v2.log.NameTransformer:日志按每个数据源类输出,还是按包。com.mchange.v2.log.PackageNames表示按包,默认的方式按类的方式
    com.mchange.v2.log.jdk14logging.suppressStackWalk:是否显示哪些类,哪些方法产生的日志,true表示不显示,false表示显示,默认值为true。

C3P0.properties的方式

##-------------------------------日志配置--------------------------------------##
# 日志的实现方式
com.mchange.v2.log.MLog=log4j
# 日志的级别,OFF,SERVER,WARNING,INFO,FINE,FINER,FINEST,ALL
com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL=All
# 日志按包输出
com.mchange.v2.log.NameTransformer=com.mchange.v2.log.PackageNames
# determine the class and method from which a log message was generated,当为true时,不打印这些日志信息
com.mchange.v2.log.jdk14logging.suppressStackWalk=true

加载配置项的方式

代码方式:通过new实例化dataSource,调用setXX方法。

 package com.rain.core;

 import java.beans.PropertyVetoException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources; public class C3P0DataSourceSample {
private static final String masterOraclejdbcUrl =
"jdbc:oracle:thin:@localhost:1521:masteroracle";
private static final String orclJdbcUrl = "jdbc:oracle:thin:@localhost:1521:orcl";
private static final String driverClassName = "oracle.jdbc.driver.OracleDriver";
private static final String user = "system";
private static final String password = "password"; public static void main(String[] args) throws Exception {
// 创建数据源对象
ComboPooledDataSource dataSource = createByInitInstance();
// 配置数据源
// configDataSource(dataSource);
// 打印数据源信息
printDataSourceInfo(dataSource);
// 运行测试用例
runSQLTest(dataSource);
} /** -------------------------创建数据源------------------------- **/
/**
* 通过实例化的方式来获取数据源
*
* @return
* @throws PropertyVetoException
* @throws SQLException
*/
public static ComboPooledDataSource createByInitInstance()
throws PropertyVetoException, SQLException {
// 创建实例
ComboPooledDataSource dataSource = new ComboPooledDataSource("");
// 连接时配置
// dataSource = connDatabaseConfig(dataSource, "masterOracle");
return dataSource;
} /**
* 创建多个数据源,每个数据源通过名字区分
*
* @return
* @throws IOException
* @throws SQLException
* @throws PropertyVetoException
*/
public static ComboPooledDataSource createMultiDataSource()
throws IOException, SQLException, PropertyVetoException {
// 创建数据库实例masterOracle
ComboPooledDataSource masterOracleDataSource = new ComboPooledDataSource("masterOracle");
// 连接时配置masterOracle数据源
masterOracleDataSource = connDatabaseConfig(masterOracleDataSource, "masterOracle");
// 创建数据库实例orcl
ComboPooledDataSource orclDataSource = new ComboPooledDataSource("orcl");
// 连接时配置orcl数据源
orclDataSource = connDatabaseConfig(orclDataSource, "orcl");
// 执行测试语句
runSQLTest(masterOracleDataSource);
// 执行测试语句
runSQLTest(orclDataSource);
return masterOracleDataSource;
} /**
* 通过DataSources工厂方式建立连接
*
* @return
* @throws SQLException
*/
public static DataSource createByFactory() throws SQLException {
// 创建unpooled的数据源
DataSource ds_unpooled =
DataSources.unpooledDataSource(masterOraclejdbcUrl, user, password);
// pooled数据源的参数
Map<String, String> paramMap = new HashMap<>();
ComboPooledDataSource pooled =
(ComboPooledDataSource) DataSources.pooledDataSource(ds_unpooled, paramMap);
runSQLTest(pooled);
pooled.close();
DataSources.destroy(pooled);
return pooled;
} /** -----------------------配置数据源----------------------------- **/
/**
* 配置数据源
*
* @param dataSource
* @return
* @throws PropertyVetoException
*/
public static ComboPooledDataSource configDataSource(ComboPooledDataSource dataSource)
throws PropertyVetoException {
// 连接数据库的必要属性
connDatabaseConfig(dataSource,"masterOracle");
// 连接池的相关配置
connPoolConfig(dataSource);
// 连接对象的生命周期配置
connAgeConfig(dataSource);
// 测试连接的配置
connTestConfig(dataSource);
// statement对象的配置
statementConfig(dataSource);
// 重连配置
reconnConfig(dataSource);
// 连接的监听类配置
connListenerConfig(dataSource);
// 事务的配置
tranConfig(dataSource);
// 调试模式
debugMode(dataSource);
// 线程配置
threadConfig(dataSource);
return dataSource;
} /**
* 连接池的配置 initialPoolSize:连接池的初始值 maxPoolSize:连接池的最大值 minPoolSize:连接池的最小值
*
* @param dataSource
*/
private static void connPoolConfig(ComboPooledDataSource dataSource) {
// 连接池的初始值,默认值为3
dataSource.setInitialPoolSize(10);
// 连接池的最大值,默认值为0
dataSource.setMaxPoolSize(20);
// 连接池的最小值,最小值为3
dataSource.setMinPoolSize(1);
// 连接池的递增值,默认值为3
dataSource.setAcquireIncrement(5);
} /**
* 连接池生命周期配置,连接池首先从数据库中获取连接,用户请求时从连接池中获取连接。默认值为0,表示永不过期。 maxConnectionAge:
* 连接对象生命的最大值,超过此时间,连接池会销毁连接对象,连接池变小。单位为秒,建议设置1800或更多 maxIdleTime:
* 空闲连接在连接池中的超时时间,超过此时间,连接池将会销毁连接对象。单位为秒,建议设置1800或更多
* maxIdleTimeExcessConnections:当连接池不处于过载状态时,空闲连接对象生命的最大值。
* unreturnedConnectionTimeout:当连接对象在一定时间内无法回收,则创建新连接对象,销毁旧连接对象
*
* @param dataSource
*/
private static void connAgeConfig(ComboPooledDataSource dataSource) {
// 连接对象生命的最大值,它指绝对时间。从创建开始时计算,默认值为0
dataSource.setMaxConnectionAge(10 * 60 * 60);
// 空闲连接的超时时间,从连接池变为空闲状态开始计算
dataSource.setMaxIdleTime(1800);
// 空闲连接对象生命的最大值
dataSource.setMaxIdleTimeExcessConnections(60);
// 连接对象的最大使用时间,设置为2小时
dataSource.setUnreturnedConnectionTimeout(2 * 60 * 60);
} /**
* 连接测试配置。 automaticTestTable:测试连接时使用的数据库表 ,默认值为null。connectionTesterClassName:测试连接时使用的类名称
* idleConnectionTestPeriod:测试连接间隔时间。在此段时间内不进行连接测试。 preferredTestQuery:连接测试使用的SQL语句。默认语句为select
* 1 from dual。 testConnectionOnCheckin:从连接池回收连接对象时测试连接。默认值为false
* testConnectionOnCheckOut:从连接池取出连接对象时测试连接。默认值为false。
* forceSynchronousCheckins:连接池回收连接对象时是同步,还是异步,默认是异步。默认值为false
*
* @param dataSource
* @throws PropertyVetoException
*/
private static void connTestConfig(ComboPooledDataSource dataSource)
throws PropertyVetoException {
// 连接测试使用的数据库表,默认值为Null
dataSource.setAutomaticTestTable("dual");
// 连接测试使用的SQL语句,默认使用Connection对象的isAlive方法,所以一般不设置此值,默认值为null
dataSource.setPreferredTestQuery("select 1");
// 从连接池取出连接时测试连接,默认值为false
dataSource.setTestConnectionOnCheckout(true);
// 从连接池回收连接时测试连接,默认值为false。
dataSource.setTestConnectionOnCheckin(true);
// 测试连接的间隔时间,默认值为0
dataSource.setIdleConnectionTestPeriod(60);
// 测试连接使用的类名称
dataSource.setConnectionTesterClassName("com.rain.Tester.ConnectionTesterSample");
} /**
* 连接池中PreparedStatement对象的配置 PreparedStatement对象的配置。 maxStatements:连接池拥有PreparedStatement对象的总数。
* maxStatementsPerConnections:每个连接拥有PreparedStatement对象的数目。
*
* @param dataSource
*/
private static void statementConfig(ComboPooledDataSource dataSource) {
// 设置PreparedStatement对象的总数,默认值为0,表示关闭
dataSource.setMaxStatements(100);
// 设置每个连接拥有Statement对象的数目,默认值为0,表示关闭。
dataSource.setMaxStatementsPerConnection(15);
} /**
* 当连接失败后,重新连接的配置。 acquireRetryAttempts:重连的次数。 acquireRetryDelay:重连的时间间隔。单位为毫秒
* breakAfterAcquireFailure:重连失败后,如果此值设置为false,数据源对象不会销毁,设置为false。数据源被销毁。
* checkoutTimeout:等待连接响应的时间。
*/
private static void reconnConfig(ComboPooledDataSource dataSource) {
// 设置重连次数为3,默认值为30
dataSource.setAcquireRetryAttempts(3);
// 设置重连的时间间隔为2秒,默认值为1000
dataSource.setAcquireRetryDelay(2000);
// 等待连接响应的超时时间。默认值为0表示永远不超时
dataSource.setCheckoutTimeout(4);
// 重连失败后,销毁数据源。默认值为false
dataSource.setBreakAfterAcquireFailure(true);
} /**
* 设置连接对象的监听类,该类有四个方法 onAcquire:表示当连接池从数据库中获得连接时 onDestory:表示当连接池销毁连接对象时 onCheckOut:从连接池中获取连接对象时
* onCheckIn:连接池回收连接对象时。
*/
private static void connListenerConfig(ComboPooledDataSource dataSource) {
// 设置连接对象的监听类
dataSource.setConnectionCustomizerClassName("com.rain.Tester.ConnCustomrizerSample");
} /**
* 连接对象的事务配置 autoCommitOnClose:是否自动提交事务,true为是,false为否,默认为否 forceIgnoreUnresolvedTransactions
* 回收连接时,是否强制回滚或提交事务,默认为false。一般不设置此值, 例如由Spring来管理事务
*
* @param dataSource
*/
private static void tranConfig(ComboPooledDataSource dataSource) {
// 关闭自动提交事务,默认值为false
dataSource.setAutoCommitOnClose(false);
// 回收连接时,是否强制回滚或提交事务,设置为false。
dataSource.setForceIgnoreUnresolvedTransactions(false); } /**
* 调试模式的设置 debugUnreturnedConnectionStackTraces:从连接池获取连接对象时,打印所有信息 *
* @param dataSource
*/
private static void debugMode(ComboPooledDataSource dataSource) {
// 从连接池获取连接对象时,打印所有信息
dataSource.setDebugUnreturnedConnectionStackTraces(true);
} /**
* 类加载器的设置。 contextClassLoaderSource:可选值为caller,none,library。默认值为caller,一般不设置此值。
* privilegeSpawnedThreads:
*
* @param dataSource
*/
private static void classLoaderConfig(ComboPooledDataSource dataSource) {
// dataSource.getContext
} /**
* 连接池的线程设置 numHelperThread:连接池拥有的线程数量 maxAdministrativeTaskTime:线程执行的超时时间。
*
* @param dataSource
*/
private static void threadConfig(ComboPooledDataSource dataSource) {
// 设置线程数量为10,默认值为3
dataSource.setNumHelperThreads(10);
// 设置线程的超时时间,默认值为0,设置为5分钟
dataSource.setMaxAdministrativeTaskTime(5 * 60);
} /**
* 连接池的日志配置,mchange-log.properties提供默认配置
*
* @param dataSource
*/
private static void logConfig(ComboPooledDataSource dataSource) {
// 设置com.mchange.v2.log.MLog
// 设置com.mchange.v2.log.jdk14logging.suppressStackWalk
// 设置com.mchange.v2.log.NameTransformer
// 设置com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL,可选值为
// OFF,SERVER,WARNING,INFO,FINE,FINER,FINEST,ALL
} /**
* 其他配置项
*
* @param dataSource
*/
private static void otherConfig(ComboPooledDataSource dataSource) {
// 设置factoryClassLocation
// 设置forceSynchronousCheckins
// statementCacheNumDeferredCloseThreads
// com.mchange.v2.c3p0.cfg.xml
// com.mchange.v2.c3p0.impl.DefaultConnectionTester.querylessTestRunner
// com.mchange.v2.c3p0.impl.DefaultConnectionTester.isValidTimeout
} /**
* 打印连接池的属性
*
* @param dataSource
*/
private static void printDataSourceInfo(ComboPooledDataSource dataSource) {
// 连接时的必要属性
System.out.println("——————————————————————————————————————————————————————————————————————");
System.out.println("||-------------------连接数据库的必要属性-----------------||");
System.out.println("数据源的驱动类名称:" + dataSource.getDriverClass());
System.out.println("数据源的连接URL:" + dataSource.getJdbcUrl());
System.out.println("数据源的连接用户名:" + dataSource.getUser());
System.out.println("数据源的连接密码:" + dataSource.getPassword());
System.out.println("数据源的Id:" + dataSource.getIdentityToken());
// 连接池的基本配置
System.out.println("——————————————————————————————————————————————————————————————————————");
System.out.println("||-------------------连接池大小配置---------------------||");
System.out.println("连接池的初始需求量大小:" + dataSource.getInitialPoolSize());
System.out.println("连接池的最大值:" + dataSource.getMaxPoolSize());
System.out.println("连接池的最小值:" + dataSource.getMinPoolSize());
System.out.println("当无可用连接时,连接池需求量的递增值:" + dataSource.getAcquireIncrement());
// 连接对象的生命周期配置
System.out.println("——————————————————————————————————————————————————————————————————————");
System.out.println("||-------------------连接对象的生命周期--------------------||");
System.out.println("连接对象的最大生存时间,从创建连接对象时开始计时:" + dataSource.getMaxConnectionAge());
System.out.println("空闲连接对象的超时时间,从连接对象变为空闲状态开始计时:" + dataSource.getMaxIdleTime());
System.out.println("当连接池负载较低时,空闲连接对象的最大生命年龄:" + dataSource.getMaxIdleTimeExcessConnections());
System.out.println("从连接池获取连接对象之后,连接对象的超时时间:"+dataSource.getUnreturnedConnectionTimeout());
// 测试连接的配置
System.out.println("——————————————————————————————————————————————————————————————————————");
System.out.println("||-------------------测试连接的配置----------------------||");
System.out.println("测试连接使用的数据库表:" + dataSource.getAutomaticTestTable());
System.out.println("测试连接使用的SQL语句:" + dataSource.getPreferredTestQuery());
System.out.println("从连接池中获取连接时是否进行连接测试:"
+ convertBooleanToStr(dataSource.isTestConnectionOnCheckout()));
System.out.println("从连接池中回收连接时是否进行连接测试:"
+ convertBooleanToStr(dataSource.isTestConnectionOnCheckin()));
System.out.println("测试连接的时间间隔:" + dataSource.getIdleConnectionTestPeriod() + "秒");
System.out.println("测试连接使用的类名称:" + dataSource.getConnectionTesterClassName());
// 重连配置
System.out.println("——————————————————————————————————————————————————————————————————————");
System.out.println("||-------------------重连配置-----------------||");
System.out.println("连接失败后,尝试重连的次数:" + dataSource.getAcquireRetryAttempts());
System.out.println("重连的时间间隔:" + dataSource.getAcquireRetryDelay()+"毫秒");
System.out.println("用户等待连接的超时时间:" + dataSource.getCheckoutTimeout());
System.out.println(
"重连失败后,是否销毁数据源:" + convertBooleanToStr(dataSource.isBreakAfterAcquireFailure()));
// 缓存preparedStatement对象的配置
System.out.println("——————————————————————————————————————————————————————————————————————");
System.out.println("||-------------------缓存preparedStatement对象的配置-----------------||");
System.out.println("连接池拥有PreparedStatement对象的总数:" + dataSource.getMaxStatements());
System.out.println(
"每个连接拥有PreparedStatement对象的数量:" + dataSource.getMaxStatementsPerConnection());
// 线程设置
System.out.println("——————————————————————————————————————————————————————————————————————");
System.out.println("||-------------------线程设置--------------------------||");
System.out.println("连接池拥有的线程数量:" + dataSource.getNumHelperThreads());
System.out.println(
"线程执行的超时时间:" + dataSource.getMaxAdministrativeTaskTime());
// 设置事务
System.out.println("——————————————————————————————————————————————————————————————————————");
System.out.println("||-------------------事务配置---------------------------||");
System.out
.println("连接对象的事务是否自动提交:" + convertBooleanToStr(dataSource.isAutoCommitOnClose()));
System.out.println("回收连接对象时,是否强制提交和回滚事务:"
+ convertBooleanToStr(dataSource.isForceIgnoreUnresolvedTransactions()));
// 设置调试模式
System.out.println("——————————————————————————————————————————————————————————————————————");
System.out.println("||-------------------调试模式配置-----------------------||");
System.out.println("从连接池获取连接对象时,是否打印所有信息:"
+ convertBooleanToStr(dataSource.isDebugUnreturnedConnectionStackTraces()));
// 监听类
System.out.println("——————————————————————————————————————————————————————————————————————");
System.out.println("||-------------------监听类名称-----------------||");
System.out.println("连接对象的监听类名称:" + dataSource.getConnectionCustomizerClassName()); } /**
* 运行测试用例,执行select 1 from dual 语句。
*
* @param dataSource
* @throws SQLException
*/
private static void runSQLTest(ComboPooledDataSource dataSource) throws SQLException {
// 建立连接
Connection conn = dataSource.getConnection();
// 创建Statement对象
Statement statement = conn.createStatement();
// 处理结果集
ResultSet rs = statement.executeQuery("select 1 from dual");
printResultSet(rs);
} private static void printResultSet(ResultSet rs) throws SQLException {
while (rs.next()) {
System.out.println("返回结果集为:" + rs.getInt(1));
}
} /**
* 连接数据库时的必要配置, driverClass:驱动类 jdbcUrl:数据库实例url,格式为jdbc:subprotocol:subname
* user:用户名,其他数据源有时候使用username表示,拥有相同的含义。 password:密码,用户密码
*
* @param dataSource
* @return
* @throws PropertyVetoException
*/
public static ComboPooledDataSource connDatabaseConfig(ComboPooledDataSource dataSource,
String dsName) throws PropertyVetoException {
String jdbcUrl = null;
switch (dsName) {
case "masterOracle":
jdbcUrl = masterOraclejdbcUrl;
break;
case "orcl":
jdbcUrl = orclJdbcUrl;
break;
default:
break;
}
// 设置数据库url
dataSource.setJdbcUrl(jdbcUrl);
// 设置数据库驱动类
dataSource.setDriverClass(driverClassName);
// 设置用户名
dataSource.setUser(user);
// 设置密码
dataSource.setPassword(password);
// 输出dataSourceName,在初始化ComboPooledDataSource时,字符串参数作为数据源名称,
dataSource.getDataSourceName();
return dataSource;
} /**
* 将布尔值true转换为是,布尔值false转换为否
*
* @param value
* @return
*/
private static String convertBooleanToStr(boolean value) {
if (value) {
return "是";
} else {
return "否";
}
}
}

Properties方式:在类加载路径下,配置项有c3p0前缀

##-------------------------------数据库连接属性-----------------------------------##
# 驱动类名称
c3p0.driverClass=oracle.jdbc.driver.OracleDriver
# 数据库实例url地址
c3p0.jdbcUrl=jdbc:oracle:thin:@localhost:1521:masteroracle
# 用户名
c3p0.user=system
# 密码
c3p0.password=password
##-------------------------------调试模式--------------------------------------##
# 当从连接池获取连接对象时,打印所有信息。
c3p0.debugUnreturnedConnectionStackTraces=true
##-------------------------------日志配置--------------------------------------##
# 日志的实现方式
#com.mchange.v2.log.MLog=log4j
# 日志的级别,OFF,SERVER,WARNING,INFO,FINE,FINER,FINEST,ALL
com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL=All
# 日志按包输出
com.mchange.v2.log.NameTransformer=com.mchange.v2.log.PackageNames
# determine the class and method from which a log message was generated,当为true时,不打印这些日志信息
com.mchange.v2.log.jdk14logging.suppressStackWalk=true
##-------------------------------连接池配置-------------------------------------##
# 连接池拥有连接对象的初始值,这种情形下只是Acquire(需求)的初始值,真正创建对象会根据Acquire来按需创建
c3p0.initialPoolSize=10
# 连接池拥有连接对象的最大值,默认值为3
c3p0.maxPoolSize=20
# 连接池拥有连接对象的最小值,默认值为3
c3p0.minPoolSize=5
# 当无空闲连接时,新创建的连接数,默认值为3
c3p0.acquireIncrement=3
##-------------------------------连接生命周期--------------------------##
# 连接对象的最大生存时间,起始时间从连接池从数据库中创建连接对象开始计算。0表示永远不销毁
c3p0.maxConnectionAge=0
# 空闲连接对象的超时时间,起始时间从连接对象状态变为空闲时起计算。
c3p0.maxIdleTime=1800
# 当连接池不处于满载状态时,空闲连接对象的最大生存时间,设置此值,可以快速的减少连接池的大小
c3p0.maxIdleTimeExcessConnections=60
# 连接对象回收的超时时间,当连接池无法在一定时间内回收连接对象时,销毁旧对象,重新创建新对象
c3p0.unreturnedConnectionTimeout=600
##-------------------------------测试连接配置项----------------------------------##
# 从连接池中获取连接对象时进行连接测试
c3p0.testConnectionOnCheckout=true
# 从连接池回收对象时进行连接测试
c3p0.testConnectionOnCheckin=true
# 连接测试的间隔,在这一段时间内不进行连接测试
c3p0.idleConnectionTestPeriod=60
# 连接测试时使用的类,设置此值时忽略preferredTestQuery,automaticTestTable等属性值
#c3p0.connectionTesterClassName=com.rain.Tester.ConnectionTesterSample
# 测试的SQL语句
c3p0.preferredTestQuery=select 1
# 连接测试时使用的数据库表
c3p0.automaticTestTable=test
##-------------------------------重新连接---------------------------------------##
# 重新连接的次数
c3p0.acquireRetryAttempts=5
# 重新连接的时间间隔,单位为毫秒
c3p0.acquireRetryDelay=3000
# 等待连接响应的超时时间
c3p0.checkoutTimeout=120
# 当连接失败时,是否销毁数据源对象,true表示是,false表示否
c3p0.breakAfterAcquireFailure=true
##-------------------------------statement对象相关配置---------------------------##
# c3p0拥有的PreparedStatement对象的总数
c3p0.maxStatements=100
# 每个连接拥有PreparedStament对象的数量
c3p0.maxStatementsPerConnection=10
# 当Connection对象关闭时,启动额外线程确保statement对象关闭
# This parameter should only be set if you observe that attempts by c3p0 to close() cached statements freeze
statementCacheNumDeferredCloseThreads=1
##-------------------------------线程池----------------------------------------##
# 连接池拥有的线程数量
c3p0.numHelperThreads=5
# 线程执行的最大时间
c3p0.maxAdministrativeTaskTime=600
# 启动独立的线程来在连接被连接池回收阶段进行测试
forceSynchronousCheckins=true
##-------------------------------事务-----------------------------------------##
# 交给Spring去管理事务,默认不配置这些项
# 连接关闭时,是否自动提交事务
c3p0.autoCommitOnClose=false
# 连接回收时,是否强制提交或者回滚当前连接拥有的事务,默认不配置。
c3p0.forceIgnoreUnresolvedTransactions=false
##-------------------------------监听类---------------------------------------##
c3p0.connectionCustomizerClassName=com.rain.Tester.ConnCustomrizerSample
##-------------------------------类加载器配置------------------------------------##
# contextClassLoaderSource should be set to one of caller, library, or none
c3p0.contextClassLoaderSource=caller
# privilegeSpawnedThreads is a boolean, false by default. Set this to true so that c3p0's Threads use the
# c3p0 library's AccessControlContext, rather than an AccessControlContext that may be associated with
# the client application and prevent its garbage collection.
privilegeSpawnedThreads=false

xml方式:com.mchange.v2.c3p0.cfg.xml指定c3p0-config.xml的路径

System属性:System.setProperty(key,value)。

验证

代码方式的执行结果

——————————————————————————————————————————————————————————————————————
||-------------------连接数据库的必要属性-----------------||
数据源的驱动类名称:oracle.jdbc.driver.OracleDriver
数据源的连接URL:jdbc:oracle:thin:@localhost:1521:masteroracle
数据源的连接用户名:system
数据源的连接密码:password
数据源的Id:1hge1639oxiibou10417lr|7506e922
——————————————————————————————————————————————————————————————————————
||-------------------连接池大小配置---------------------||
连接池的初始需求量大小:10
连接池的最大值:20
连接池的最小值:5
当无可用连接时,连接池需求量的递增值:3
——————————————————————————————————————————————————————————————————————
||-------------------连接对象的生命周期--------------------||
连接对象的最大生存时间,从创建连接对象时开始计时:0
空闲连接对象的超时时间,从连接对象变为空闲状态开始计时:1800
当连接池负载较低时,空闲连接对象的最大生命年龄:60
从连接池获取连接对象之后,连接对象的超时时间:600
——————————————————————————————————————————————————————————————————————
||-------------------测试连接的配置----------------------||
测试连接使用的数据库表:test
测试连接使用的SQL语句:select 1
从连接池中获取连接时是否进行连接测试:是
从连接池中回收连接时是否进行连接测试:是
测试连接的时间间隔:60秒
测试连接使用的类名称:com.mchange.v2.c3p0.impl.DefaultConnectionTester
——————————————————————————————————————————————————————————————————————
||-------------------重连配置-----------------||
连接失败后,尝试重连的次数:5
重连的时间间隔:3000毫秒
用户等待连接的超时时间:120
重连失败后,是否销毁数据源:是
——————————————————————————————————————————————————————————————————————
||-------------------缓存preparedStatement对象的配置-----------------||
连接池拥有PreparedStatement对象的总数:100
每个连接拥有PreparedStatement对象的数量:10
——————————————————————————————————————————————————————————————————————
||-------------------线程设置--------------------------||
连接池拥有的线程数量:5
线程执行的超时时间:600
——————————————————————————————————————————————————————————————————————
||-------------------事务配置---------------------------||
连接对象的事务是否自动提交:否
回收连接对象时,是否强制提交和回滚事务:否
——————————————————————————————————————————————————————————————————————
||-------------------调试模式配置-----------------------||
从连接池获取连接对象时,是否打印所有信息:是
——————————————————————————————————————————————————————————————————————
||-------------------监听类名称-----------------||
连接对象的监听类名称:com.rain.Tester.ConnCustomrizerSample

参考资料

C3p0 —— JDBC 3 Connection and Statement Pooling   http://www.mchange.com/projects/c3p0

数据库程序接口——JDBC——功能第二篇——数据源之C3P0数据源的相关教程结束。

《数据库程序接口——JDBC——功能第二篇——数据源之C3P0数据源.doc》

下载本文的Word格式文档,以方便收藏与打印。