c3p0数据库连接池手册

定义

c3p0是一个成熟的、高并发的JDBC连接池,它随Hibernate一同分发,希望提供一个优秀的J2EE企业级应用的数据源实现。

使用情形

c3p0:

使用方法

必备环境

c3p0-0.9.5-pre8需要1.6.x或者更高版本的Java运行环境。

安装

lib/c3p0-0.9.5-pre8.jarlib/mchange-commons-java-0.27.jar两个文件放入你的CLASSPASS下(或者你的类加载器能够加载的任何地方)。

快速使用

创建数据源:

import com.mchange.v2.c3p0.*;
...
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver
cpds.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
cpds.setUser("dbuser");
cpds.setPassword("dbpassword"); 

[可选]:如果你需要开启PreparedStatement池,你必须设置maxStatements和/或maxStatementsPerConnection两个值(默认都为0)。

cpds.setMaxStatements(180);

数据源底层的连接池将使用默认参数创建,你可以对数据源进行任何操作。你可以根据你的喜好将数据源绑定到JNDI命名空间或者直接使用它。

当你使用完毕的时候,你可以销毁数据源:

cpds.close();

进阶使用

c3p0提供标准的JDBC2数据源对象。用户可以在创建数据源对象时控制与池有关的、与命名有关的属性等。所有的池管理操作在数据源对象被创建后都是对用户完全透明的。

创建c3p0数据源有三种方式:

如果不指定配置的话,c3p0将使用默认参数创建数据源。

一旦实例化成功,c3p0数据源就可以和与JNDI标准兼容的命名服务绑定。

c3p0内置了硬编码的配置,但你可以通过创建一个c3p0.properties文件并将其放置在加载c3p0的jar文件的CLASSPATH(或类加载器)的顶级目录下以覆盖配置信息。
更多的配置信息请看下一章。

实例化并配置ComboPooledDataSource

实例化一个com.mchange.v2.c3p0.ComboPooledDataSource是创建c3p0池数据源的最直接方式。这是一个JavaBean风格的,拥有一个无参数的Public构造方法的类。确保你在使用它之前设定了jdbcUrl属性。你也可以根据需要设定userpassword属性。如果你使用了未预加载的老式JDBC驱动,你还应当设定driverClass属性。

ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver cpds.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
cpds.setUser("swaldman");
cpds.setPassword("test-password");
// the settings below are optional -- c3p0 can work with defaults
cpds.setMinPoolSize(5);
cpds.setAcquireIncrement(5);
cpds.setMaxPoolSize(20);
// The DataSource cpds is now a fully configured and usable pooled DataSource
...

任何一个c3p0 DataSource的实例的初状态都取决于你提供的配置或者还原为硬编码的默认配置。

c3p0支持命名配置以配置多个数据源。

你可以构造自己的com.mchange.v2.c3p0.ComboPooledDataSource命名配置:

ComboPooledDataSource cpds = new ComboPooledDataSource("intergalactoApp");

当然,你仍然可以通过前面所述的编程方式来覆盖配置信息。

使用数据源工厂类

此外,你还可以使用静态工厂类Com.mchange.v2.c3p0.DataSources来从传统的JDBC驱动里创建未入池的数据源,并用它来构造一个池化的数据源:

DataSource ds_unpooled = DataSources.unpooledDataSource(
"jdbc:postgresql://localhost/testdb", "swaldman", "test-password");
DataSource ds_pooled = DataSources.pooledDataSource( ds_unpooled );
// The DataSource ds_pooled is now a fully configured and usable pooled DataSource.
// The DataSource is using a default pool configuration, and Postgres' JDBC driver
// is presumed to have already been loaded via the jdbc.drivers system property or an
// explicit call to Class.forName("org.postgresql.Driver") elsewhere.
...

如果你使用了这个数据源工厂类,并且想要编程式覆盖默认配置,你可以通过提供一个map来实现:

DataSource ds_unpooled = DataSources.unpooledDataSource(
"jdbc:postgresql://localhost/testdb", "swaldman", "test-password");
Map overrides = new HashMap();
overrides.put("maxStatements", "200");//Stringified property values work
overrides.put("maxPoolSize", new Integer(50)); //"boxed primitives" also work

// create the PooledDataSource using the default configuration and our overrides
ds_pooled = DataSources.pooledDataSource( ds_unpooled, overrides ); 
// The DataSource ds_pooled is now a fully configured and usable pooled DataSource,
// with Statement caching enabled for a maximum of up to 200 statements and a maximum
// of 50 Connections.
...

如果你使用命名配置,你可以指定一个命名来配置你的数据源:

// create the PooledDataSource using the a named configuration and specified overrides 
ds_pooled = DataSources.pooledDataSource(ds_unpooled, "intergalactoAppConfig", overrides ); 

查询池数据源的当前状态

c3p0数据源依赖着一个包括ComboPooledDataSource的实现和DataSources.pooledDataSource(...)方法返回对象,以及实现com.mchange.v2.c3p0.PooledDataSource所有接口的池。这使得有大量查询数据源连接池状态的方法可用。

查询数据源状态的实例代码:

// fetch a JNDI-bound DataSource
InitialContext ictx = new InitialContext();
DataSource ds = (DataSource) ictx.lookup( "java:comp/env/jdbc/myDataSource" );

// make sure it's a c3p0 PooledDataSource
if (ds instanceof PooledDataSource){
  PooledDataSource pds = (PooledDataSource) ds;
  System.err.println("num_connections:"+ pds.getNumConnectionsDefaultUser());
  System.err.println("num_busy_connections:"+pds.getNumBusyConnections
  DefaultUser());
  System.err.println("num_idle_connections:"+pds.getNumIdleConnections
  DefaultUser());
  System.err.println();
}
else
  System.err.println("Not a c3p0 PooledDataSource!");

这些状态查询方法有三种重载方式:

清理c3p0 PooledDataSources

最简单的清理c3p0 PooledDataSources的方法就是调用DataSources类的destory方法。只有PooledDataSource对象需要被清理。对非池化或非c3p0数据源调用DataSources.destory(...)方法也无妨。

DataSource ds_pooled = null;
try{
  DataSource ds_unpooled = DataSources.unpooledDataSource(
"jdbc:postgresql://localhost/testdb","swaldman","test-password");
  ds_pooled = DataSources.pooledDataSource( ds_unpooled );

  // do all kinds of stuff with that sweet pooled DataSource...
}
finally{
  DataSources.destroy( ds_pooled );
}

此外,你可以通过调用c3p0的PooledDataSource接口的close()方法来关闭DataSource对象。因此,你可以将DataSource对象转换成PooledDataSource对象然后关闭它。

static void cleanup(DataSource ds) throws SQLException{
  // make sure it's a c3p0 PooledDataSource
  if ( ds instanceof PooledDataSource){
    PooledDataSource pds = (PooledDataSource) ds;
    pds.close();
  }     
  else
    System.err.println("Not a c3p0 PooledDataSource!");
}

ComboPooledDatasourcePooledDataSource的一个实例,也能直接被它的close()方法关闭。

在用户调用close()方法而被关闭之前,未被引用的PooledDataSource实例不会被垃圾回收器调用finalize()而被关闭。自动销毁机制和通常一样,只是一种辅助方法,而不用来确保资源的清理。

创建个人的PoolBackedDataSource

你可以通过这种方法来一步步地创建一个PoolBackedDataSource(对大多数程序员来说并不必要):

如果你的驱动提供了ConnectionPoolDataSource 的实现,你只需要:

实例化并配置一个非池化的DriverManagerDataSource,之后实例化一个WrapperConnectionPoolDataSource,将非池化的数据源设置为它的nestedDataSource属性,然后将它设定为一个PoolBackedDataSource对象的connectionPoolDataSource属性。

除了使用c3p0的WrapperConeectionPoolDataSource之外,你还可以创建一个PollBackedDataSource,然 后 设 定 它 的connectionPoolDataSource属 性。第三方的ConnectionPoolDataSource不支持Statement池ConnectionCustomizers,和一些特定的 c3p0属性(第三方的 DataSource 实现可以用来替代c3p0的DriverManagerDataSource,这在功能上并没有什么明显的损失)。

原生连接(Raw Connection)和Statement操作

JDBC驱动在实现ConnectionStatement上有时定义了一些与特定厂商的,不标准的API。c3p0将这些对象包装进了一个代理里,所以你不能把c3p0返回的 ConnectionStatement 转换成特定厂商的实现。c3p0没有提供任何能够直接访问原生连接和Statement的方法,这是因为c3p0需要一直按顺序地追踪Statement和结果集的创建,来防止资源紧缺和池讹误(pool corruption)现象。

c3p0提供了一个能让你通过反射在底层的连接上来执行非标准方法的API。使用方法是:
首先将返回的Connection转 换 成 一 个C3P0ProxyConnection。然后调用rawConnectionOperation方法,然后提供一个你想要执行的 java.lang.reflect.Method对象作为这个非标准方法的参数。你提供的这个Method对象将会在第二个参数(null或者静态方法)上执行,并且使用你提供的第三个参数来完成这个方法。对目标对象和这个方法的所有参数来讲,你都可以使用 C3P0ProxyConnection.RAW_CONNECTION这个特殊的标记,它将会在方法执行前替代底层的特定厂商的Connection

C3P0ProxyStatement也提供了类似的API。

原生操作返回的所有Statement(包括PreparedCallableStatement)和ResultSet都是被c3p0所管理的,所以在其父代理连接上调用close()方法的时候它们都会被正确地清理。用户必须注意清理那些与特定厂商相关的方法返回的那些非标准的资源。

使用 Oracle特定的API在原生连接上调用静态方法的例子:

C3P0ProxyConnection castCon = (C3P0ProxyConnection) c3p0DataSource.getConnection();
Method m = CLOB.class.getMethod("createTemporary", new Class[]{Connection.class, boolean.class, int.class});
Object[] args = new Object[] {C3P0ProxyConnection.RAW_CONNECTION, Boolean.valueOf( true ), new Integer( 10 )};
CLOB oracleCLOB = (CLOB) castCon.rawConnectionOperation(m, null, args);    

C3P0 现在支持一些 Oracle 特定的方法了,在本文的其他相关中有详细的介绍。

属性配置

c3p0没有过多的必须(required)配置信息,它非常灵活可控。大多数的配置信息都是JavaBean 属性。下面就是 JavaBean 的惯例,如果有一个对象有一个类型为 T 的属性 foo,这个对象就会有类似这样的方法…

这样的方法是否成对存在,取决于这个属性是只可读的,只可写,还是可读写的。

有多种方法修改 c3p0 的属性:你可以直接在代码里通过关联一个特定的数据源来改变配置,你也可以在外部通过简单的Java属性文件(simple Java properties file),XML配置文件或系统属性来配置c3p0。通常来讲,配置文件都被命名为c3p0.propertiesc3p0-config.xml,并放置在应用的CLASSPATH的顶级路径中,但是 XML 配置文件可以被放在应用所在的文件系统的任何位置,你只需要改变 com.mchange.v2.c3p0.cfg.xml这个系统属性即可(绝对路径)。

数据源通常在使用之前被配置,比如在构造方法中配置或者在构造方法返回之后马上进
行配置。不过 c3p0 也支持使用过程中修改配置。

如果你通过调用工具类com.mchange.v2.c3p0.DataSources的工厂方法来获取数据源,并且不希望这个数据源使用默认的配置,那么你可以提供一个Map类型的参数作为配置信息[key必须是小写字母开头的属性名,value可以是字符串或者“被打包(boxed)”的Java原生类型,例如IntegerBoolean]。

所有可改变的属性在附录中都有详细的文档。

连接池基本配置

c3p0 连接池可以通过下面几个基本参数来简单地配置:

initialPoolSize, minPoolSize, maxPoolSize定义了由池管理的连接数量。请确保minPoolSize<=maxPoolSize。不合理的initialPoolSize值将会被忽略,然后使用 minPoolSize来替代。

minPoolSizemaxPoolSize的范围之内,池中的连接数量与使用模式(usage patterns)有关。当用户请求一个连接,池中又没有可用连接,并且池中的连接数量还未达到maxPoolSize的时候,池中的连接数就会增长。因为获取连接非常慢,所以成批地增加连接数量通常都很有效,而不是强制要用户在需要新连接时从头开始激活并获取一个连接。acquireIncrement属性决定了c3p0在没有可用连接时一次性获取的新连接数量。(不过c3p0绝不会因此而使连接数超过maxPoolSize值。)

当连接池测试一个连接并且发现它已失效(broken)(参考下面的配置连接测试),或者当一个连接因空闲期超过一段时间而过期,或太旧(too old)(参考管理池尺寸和连接寿命)的时候,连接池中的连接数量将会下降。

容量和连接寿命配置

C3P0 提供了大量的选项来控制池内连接数的增长或减小的速度,也可以用一些选项来决定“旧”连接是否应该主动地被替换以维持应用的可靠性。

默认情况下,连接池不会给连接设定过期时间。如果你为了保持连接“新鲜”,想要给
连接设定过期时间的话,需要设定 maxIdleTime 和/或 maxConnectionAgemaxIdleTime 定义了连接因在多少秒内未被使用而被连接池剔除的时间。maxConnectionAge 决定了所有从数据库中获取的连接将在多少秒后被连接池剔除。

maxIdleTimeExcessConnections用来最小化 c3p0 欠载(under load)时的连接数。默认情况下,在 c3p0 欠载时,c3p0 只会因连接测试失败或者连接过期而缩小池中的连接数。有一些用户需要在一些突然增大会连接数的操作之后快速地释放不必要的连接。你可以通过把maxIdleTimeExcessConnetions 设定为一个比 maxIdleTime 小得多的值来达到这个目的。超过最小连接数的那些连接会在较小的一段空闲时间之后被连接池剔除。

对设置这类超时参数有一些普通的建议:悠着点!使用连接池的重点就是尽量只从数据库中获取连接一次,然后不断重复地使用它们。大多数的数据库的连接可以一次维持若干小时。没有必要每隔几秒钟或几分钟就剔除那些空闲的连接。把maxConnectionAgemaxIdleTime 设置成 1800 (30 分钟)都是有些激进的。对于大多数数据库来讲,几个小时或许更加合理。你可以用连接测试来确保可靠性,而不是一味地剔除它们(见配置连接测试)。通常只有 maxIdleTimeExcessConnetions 这个参数可以被设置成几分钟或更短的时间。

连接测试配置

c3p0 的连接测试可以用来最小化你的应用遇到失效或过时的连接的可能性,它可以用
多种方式来进行配置。池中的连接可能会因为各种原因而变得不可用——有些 JDBC 驱动有意地对长连接设置了超时参数;后端的数据库或网络有时候会宕掉;有些连接仅仅是因为资源紧缺,驱动的漏洞或者其他原因而变得不可用。

c3p0 通过以下参数为用户提供了灵活的测试连接的方法:

idleConnetionTestPeriod, testConnectionOnCheckout testConnectionOnCheckin 决定了连接何时被测试。automaticTestTable, connectionTesterClassNamepreferredTestQuery 决定了连接怎样被测试。

当配置连接测试的时候,首先应该考虑如何减少测试的开支。默认情况下,连接通过在
与其关联的 DatabaseMetaData 对象上调用 getTables()方法来进行测试。这对所有数据库来讲都有效,因为这与数据库的视图(database schema)无关。然而,从经验上来讲,调用DatabaseMetaData.getTables()方法相对于进行一个简单的数据库查询要慢多了。

提高连接测试速度的最方便的方法就是定义 automaticTestTable 属性。c3p0 将会使用你提供的名字创建一个空的表,然后通过一个简单的查询来测试数据库。你也可以通过设定preferredTestQuery 参数来定义一个测试语句。不过你得当心点,设置 preferredTestQuery 将会导致在初始化数据源之前出现错误,如果你查询的目标表不存在的话。

高级用户可以实现一个 ConnectionTester 然 后 提 供 一 个 类 的 全 限 定 名 作 为connectionTesterClassName 属 性 来 实 现 任 何 想 要 的 连 接 测 试 。 如 果 你 想 要 使 你 的ConnectionTester 能 够 支 持 preferredTestQuery automaticTestTable 属 性 , 实 现UnifiedConnectionTester 接口即可,实现AbstractConnectionTester是最方便的。更多信息见API 文档。

检测连接最可靠的时间就是从池中取出连接的时候(check-out)。但从客户端性能的角度 来 看 , 是 这 也 是 开 销 最 大 的 。 大 多 数 应 用 将 idleConnectionTestPeriod testConnectionOnCheckIn 结合起来用就已经非常可靠了。空闲测试和将连接放回池时(check-in)的测试都是异步执行的,这就是为什么它们有更好的性能的原因。

注意,对有些应用程序来说,拥有高性能远比避免偶然发生的数据库异常更重要。默认
情况下,c3p0 不会做任何连接测试。设置一个非常长的 idleConnectionTestPeriod 值和避免check-out 与 check-out 测试是很不错的,高性能的方法。

Statement池配置

c3p0 实现了符合 JDBC 规范的透明的 PreparedStatement池。在一些情况下,Statement池能够显著地提高应用程序的性能。但在另一些情况下,Statement池的开销又会稍微的降低性能。

statement到底能不能改善性能或者能够改善多少性能还是取决于你的数据库对查询的解析,规划和优化(parsing, planning , and optimizing)。不同数据库(和 JDBC 驱动)之间在这个方面存在很大的差异。给你的应用程序在使用和不使用statement池的时候设定基准,然后比较它们来看看究竟statement能不能改善性能是个不错的点子。

你可以通过设置下面的配置参数来配置 statement 池:

maxStatement 是 JDBC 规范的标准参数。maxStatement 定义了每个数据源会缓存的PreparedStatement 的总数。池内的 Statement 总数在达到这个限制时会销毁那些最近最近最少使用的(least-recently-used)Statement。这听起来很简单,不过事实上有些奇怪,因为从概念上来讲,被缓存的 Statement 是属于单个的数据库连接的,它们并不是全局资源。为了弄清楚 maxStatements 的大小,你不应该简单地认为它就是池中 statement 的数量,你应该将你的应用程序中的最常用的 PreparedStatement 的数量乘以合理的连接数(比如在一个高负荷的应用中的 maxPoolSize 值)。

maxStatementsPerConnection 不是一个标准的配置参数,这可能会使你感觉有些不自然。它定义了连接池中每个连接最多能拥有(缓存)多少 Statement。为了避免过多的折腾,你可以把这个值设为稍大于你应用中的 PreparedStatements 数量的一个数字。

这两个值中的任何一个大于 0 的话, statement 池就会被开启。如果两个参数都大于 0,它们的限制都会被强制执行。如果只有一个参数大于 0,仅仅只有一个限制会被强制执行。

数据库故障修复配置

c3p0 被设计成(并且默认开启了)可以从临时的数据库故障中恢复,比如数据库重启或者短暂地断开网络。你可以通过以下几个属性改变对 c3p0 在获取连接时遇到的错误的处理方式:

当 c3p0 在尝试获取数据库连接失败时,会自动地重试 acquireRetryAttempts 次,每次间隔 acquireRetryDelay。如果依然失败,所有在等待这些连接的客户端将会收到一个异常,用来表示不能获取连接。请注意,如果不是所有的获取连接尝试都失败,客户端并不会收到异常,这可能在初始化尝试获取连接之后还需要一点儿时间。如果 acquireRetryAttempts 被设置为0,c3p0将会无限期地尝试获取一个新的连接,对 getConnection()的调用可能会无限阻塞下去,直到成功获取一个连接。

一旦所有的获取连接的尝试都失败,有两种可能的处理方式。默认情况下,c3p0 数据源会保持活性,然后对后续的请求作出回应。如果你将 breakAfterAcquireFailure 设置为 true的话,数据源将会在所有尝试失败后马上停止工作,并且后续的请求也会马上失败。

请注意,如果数据库重启了,一个连接池也许还维持着那些以前获取的而现在变得不可用的连接。默认情况下,这些陈旧的连接不会被马上发现并且清理掉,当一个应用程序使用它们的时候,会马上得到一个异常。设定 maxIdleTime 或者 maxConnectionAge 可以帮助你加速替换掉这些不可用的连接。(见连接寿命的管理)如果你想完全避免应用程序因此遇到异常,你必须得指定一中连接测试策略用来在客户端使用不可用连接之前就清理掉它们。(见连接测试的配置)即使使用积极的连接测试(testConnectionsOnCheckout设置为true,或者testConnectionsOnCheckintrue并且设置了一个小的 idleConnectionTestPeriod 值),你的应用程序在数据库重启的时候依然有可能遇到一个相关的异常,比如数据库在你已经将连接测试成功后才重启。

使用链接定制器管理连接生命周期

应用程序在获取连接后经常会希望能够以某些标准的方法来重复地使用这些连接。例如,通过特定厂商的 APIs 或不标准的 SQL 扩展来设定字符编码或者日期时间等行为。有时候重写标准的连接中的默认属性值是很有用的,比如重写 transactionIsolation, holdbility或者readOnly。 c3p0 提供了一个“钩子”接口,你实现它就有机会在刚刚从数据库获得连接之后,在连接被送至客户端之前,在连接返回连接池之前,在连接最终被连接池淘汰之前,修改或追踪这个连接。交给 ConnectionCustomizer 的连接是原生的,它所有的特定厂商的 API 都可以被访问。

ConnectionCustomizer 类的更多信息见 API 文档。

安装 ConnectionCustomizer 的方法就是实现这个接口,让其对 c3p0 的类加载器课件,然后设置下面这个配置属性:

ConnectionCustomizer 必须是不可变类,并且拥有一个没有参数的公开的构造方法。它不应该保存任何状态。(很少)有一些应用程序希望使用 ConnectionCustomizer 来追踪单个的数据源的行为,这些与生命周期有关的方法都能接受一个特定的数据源的“实体令牌(identityToken)”作为参数,每个 PooledDataSource 的实体令牌都是唯一的。

下面是一个简单的 ConnectionCustomizer。实现类没有必要重写 ConnectionCustomizer 接口中的所有的四个方法,只需要继承 AbstractConnectionCustomizer 类就行了。

import com.mchange.v2.c3p0.*;
import java.sql.Connection;

public class VerboseConnectionCustomizer{
    public void onAcquire( Connection c, String pdsIdt ){ 
        System.err.println("Acquired " + c + " [" + pdsIdt + "]"); 

        // override the default transaction isolation of 
        // newly acquired Connections
        c.setTransactionIsolation( Connection.REPEATABLE_READ );
    }

    public void onDestroy( Connection c, String pdsIdt ){ 
        System.err.println("Destroying " + c + " [" + pdsIdt + "]"); 
    }

    public void onCheckOut( Connection c, String pdsIdt ){ 
        System.err.println("Checked out " + c + " [" + pdsIdt + "]"); 
    }

    public void onCheckIn( Connection c, String pdsIdt ){ 
        System.err.println("Checking in " + c + " [" + pdsIdt + "]"); 
    }
}

未结束事务处理方式配置

连接池中被检查过的连接不能有任何未结束的事务与其相关联。如果用户把一个连接的
autoCommit 属性设置成 false,并且 c3p0 不能保证在这个连接上没有后续的事务工作的话,c3p0 就会在 check-in (当用户调用 close()方法)的时候调用 rollback()方法或者 commit()方法。

JDBC 在有未结束事务的连接关闭时是应该回滚事务还是应该提交事务这个问题上保持了沉默(这简直不可原谅)。在默认情况下,c3p0 会当用户在有未结束事务的连接上调用 close()方法时回滚事务。

你可以通过下面的配置参数更改这些相关行为:

如果你想要 c3p0 在连接返回连接池时(checkin )提交未结束的事务,只需要把
autoCommitOnClose 设置为 true。如果你希望自己管理这些未结束的事务的话(并且没有设置连接的 autoCommit 属性), 你可以把 forceIgnoreUnresolvedTransactions 设置为 true。我们强烈地不鼓励设置 forceIgnoreUnresolvedTransactions 的值,因为如果客户端在连接关闭前即没有回滚也没有提交事务,并且也没有开启自动提交的话,一些奇怪的不可再生的行为(unreproduceable behavior)和数据库被锁住的现象会发生。

调试和解决问题客户端应用配置

有时候客户端应用程序对关闭连接这种工作很马虎。于是最后池内连接数增长到了maxPoolSize,然后就用尽了所有连接,这种结果是这些有问题得客户端造成的。解决这个问题的正确的方法就是修复这些客户端程序。c3p0 可以帮助你找到那些偶尔不能正确地返回连接池的连接。在一些极少见并且不幸的情况下,即使你关闭了有漏洞的应用程序,你也修复不了它。c3p0 能够帮你解决这些问题。

下面的几个参数可以帮助你调试和解决有问题得客户端程序。

unreturnedConnectionTimeout 决定了从池中取出的连接能维持多少秒。 如果这个值非零,那么从池中取出的那些在超过这个限制时间的连接还没有返回池得话,就会被立刻销毁,然后在池中被替代。很显然,你必须要保证这个参数的值能够让连接有时间完成那些应该做的工作。你可以用这个参数来解决那些关闭连接失败的不可靠的客户端程序。

完 全 修 复 漏 洞 要 比 仅 仅 使 应 用 恢 复 正 常 工 作 要 好 得 多 。 除 了 设 置 了unreturnedConnectionTimeout 之外,如果你还把 debugUnreturnedConnectionStackTraces 设置为 true 的话,你将可以得到那些从池中取出的连接的轨迹栈(stack trace)。当有连接没有按时返回池的时候,轨迹栈将会被打印出来,来揭示哪里有连接没有按时返回。

避免客户热重部署中的内存泄露配置

c3p0引起了许多线程(helper threads,java.util.Timer.threads),并迟于应答池数据源的首次客户请求。默认情况下,c3p0引发的线程从这个第一次调用的线程中继承了java.security.AccessControlContext和contextClassLoader的特性。如果该线程来自某个需要热取消部署的客户端,这些引用可能会被划分为一个ClassLoader以免被垃圾回收而终止取消部署程序。

c3p0提供了两个相关的参数:

    • contextClassLoaderSource
  • contextClassLoaderSource应当设置一个caller或library或为空。(默认是一个caller)如果使用c3p0的ClassLoader将它设置为一个library,那么需要重部署的客户端将不再包含引用。

    privilegeSpawndThreads是一个默认为false的布尔值。若将它设置为true,那么c3p0的线程将使用c3p0库中的AccessControlContext,而不是可能和客户端程序相关联从而阻止垃圾回收的 AccessControlContext。

    其他数据源配置

    在附录中查看以下几个配置参数的更多信息:

    numHelperThreadsmaxAdministrativeTaskTime 帮助你配置数据源线程池的行为。默认情况下,每个数据源仅有三个助手线程(helper threads)。如果性能看起来被高负荷工作拖慢,或者你通过 JMX 观察到或直接检测出了“附加任务(pending tasks)”数量超过了0 的话,把numHelperThreads 的值提高试试吧。

    maxAdministrativeTaskTime 可能对那些面临无限挂起的任务或者出现明显的死锁信息的用户有帮助。(更多信息见附录)

    如果所有的连接都从池中取了出去,客户端不能立即得到连接的话,checkoutTimeout限制了客户端会为得到一个连接等待多久。usesTraditionalReflectiveProxies 这个参数很少用到,它将允许你使用一种陈旧的,现在已经被取代的由 C3P0 生成的代理对象。(C3P0 以前使用反射和动态代理,而现在为了提升性能,使用了字节码生成,非反射的实现。 )如果客户端没有在本地安装 c3p0,并且 c3p0 的数据源是以一种引用的形式从 JNDI 里得到的,factoryClassLocation就能用来甄别 c3p0 的哪些类是可以被下载下来的。

    通过JMX配置和管理c3p0配置

    如果在你的环境中有 JMX 类库和 JMX MbeanServer(它们在 JDK 1.5 以上版本已经被包括了进去),你可以通过 JMX 管理工具(比如 JDK 1.5 内置的 jconsole)来检测和配置 c3p0。你会发现 c3p0 在 com.mchange.v2.c3p0下注册了很多 MBean,有一个MBean是整个库的汇总(叫做 C3P0Registry),每个你部署的 PooledDataSource 也对应着一个MBean。你可以通过这个 PooledDataSourceMBean来查看或者修改你的配置信息,追踪连接、Statement、线程池和其他的池与数据源的活动。(你可能需要查看 PoolDataSource 的 API 文档来获取它的可用的操作。)

    c3p0中名为PooledDataSourcesmbeans将会连同dataSourceName属性一同注册。如果你配置了这个属性,可以确保语义等价的数据源在程序重启时是可分辨的。

    如果你希望从单个MBean server中监控多个c3p0设施,你可以自定义JMX中出现的C3P0Registry下的名称。你可以c3p0.properties 配置文件或HOCON config中这样来配置系统文件:

    com.mchange.v2.c3p0.management.RegistryName=myRegistryName

    如果你不需要 c3p0 在你的 JMX 环境下注册 MBean ,你可以c3p0.properties 配置文件或HOCON config中这样来配置系统文件:

    com.mchange.v2.c3p0.management.ManagementCoordinator=com.mchange.v2.c3p0.management.NullManagementCoordinator 

    日志配置

    c3p0 使用了一种与 jakarta commons-logging 很相似的日志类库。日志信息可以传给流行的日志类库 log4j, JDK 1.4 中推荐的标准日志设备或者 System.err。差不多所有的配置都可以在你喜欢的那些高层的日志类库中完成。只有少数几个配置是 c3p0 的日志所特有的,并且使用默认配置就行了。和日志相关的配置参数可能在你的c3p0.properties文件里,或者在你CLASSPATH的顶级目录中的 mchange-log.properties 文件里,也有可能在系统属性里定义。(下面的日志配置参数可能不能在 c3p0-config.xml 中定义!)。见下面的文本框。

    c3p0 的日志行为会被一些编译期选项(build-time options)影响。如果编译期选项c3p0.debug 被设置成 false,所有低于 INFO 级别的日志信息将会被忽略。编译期选项 c3p0.trace能够控制低于 INFO 级别的日志信息的报告颗粒细度。目前来讲,c3p0 的发行版本的二进制文件都是把 debug 设置成 true,把 trace 设置成最大值 10 来进行编译的。不过最终可能会在发行版中把 debug 设置为 false。[就目前来讲,日志级别检查(logging level-checks)对性能的影响是很小的, 编译期间对这些信息的控制都相当灵活,你也能够让你的日志类库来控制哪些信息是要被记录的。]当 c3p0 启动的时候,那些 debugtrace 的编译期的值也会随着版本和编译时间被记录。

    com.mchange.v2.log.MLog
    Determines which library c3p0 will output log messages to. By default, if log4j is available,
    it will use that library, otherwise if jdk1.4 logging apis are available it will use those, 
    and if neither are available, it will use a simple fallback that logs to System.err. 
    If you want to directly control which library is used, you may set this property to one of:
            com.mchange.v2.log.log4j.Log4jMLog
            com.mchange.v2.log.slf4j.Slf4jMLog
            com.mchange.v2.log.jdk14logging.Jdk14MLog
            com.mchange.v2.log.FallbackMLog
        Alternatively, the following abbreviations are supported:
            log4j
            slf4j
            jul, jdk14, java.util.logging
            fallback
        You may also set this property to a comma separated list of any mix the above alternatives, 
        to define an order of preference among logging libraries.
    com.mchange.v2.log.jdk14logging.suppressStackWalk
    Under JDK standard logging, the logging library may inspect stack traces to determine the 
    class and method from which a log message was generated. That can be helpful, but it is also 
    slow. Setting this configuration parameter to true will suppress this stack walk, and reduce 
    the overhead of logging. This property now defaults to true, and logger names are logged in 
    place of class names. To return to the original slower but more informative approach, explicitly 
    set the property to false.
    com.mchange.v2.log.NameTransformer
    By default, c3p0 uses very fine-grained logging, in general with one logger for each c3p0 
    class. For a variety of reasons, some users may prefer fewer, more global loggers. You may 
    opt for one-logger-per-package by setting com.mchange.v2.log.NameTransformer to the value 
    com.mchange.v2.log.PackageNames. Advanced users can also define other strategies for 
    organizing the number and names of loggers by setting this variable to the fully-qualified 
    class name of a custom implementation of the com.mchange.v2.log.NameTransformer interface.
    com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL
    If, whether by choice or by necessity, you are using c3p0's System.err fallback logger, you 
    can use this parameter to control how detailed c3p0's logging should be. Any of the following 
    values (taken from the jdk1.4 logging library) are acceptable:
            OFF
            SEVERE
            WARNING
            INFO
            CONFIG
            FINE
            FINER
            FINEST
            ALL
        This property defaults to INFO.

    命名配置

    你可以定义命名配置以扩充和重写定义的默认配置。当你实例化一个c3p0池化数据源时,无论是通过ComboPooledDataSource构造器还是通过DataSources工厂类构造,你都可以替换它的名字。例如:
    通过ComboPooledDataSource

    ComboPooledDataSource cpds = new ComboPooledDataSource("intergalactoApp");

    通过DataSources工厂类:

    DataSource ds_pooled = DataSources.pooledDataSource( ds_unpooled, "intergalactoApp" );

    你可以这样定义命名配置:
    在属性类型的配置文件中:

    # define default-config param values
    c3p0.maxPoolSize=30
    c3p0.minPoolSize=10
    
    # define params for a named config called intergalactoApp
    c3p0.named-configs.intergalactoApp.maxPoolSize=1000
    c3p0.named-configs.intergalactoApp.minPoolSize=100
    c3p0.named-configs.intergalactoApp.numHelperThreads=50
    
    # define params for a named config called littleTeenyApp
    c3p0.named-configs.littleTeenyApp.maxPoolSize=5
    c3p0.named-configs.littleTeenyApp.minPoolSize=2

    在HOCON配置文件中:

    c3p0 {
        maxPoolSize=30
        minPoolSize=10
    
        named-configs {
            intergalactoApp {
                maxPoolSize=1000
                minPoolSize=100
                numHelperThreads=50
            }
            littleTeenyApp {
                maxPoolSize=5
                minPoolSize=2
            }
        }
    }

    在XML配置文件中:

    <c3p0-config>
    
        <default-config>
            <property name="maxPoolSize">30</property>
            <property name="minPoolSize">10</property>
        </default-config>
    
        <named-config name="intergalactoApp">
            <property name="maxPoolSize">1000</property>
            <property name="minPoolSize">100</property>
            <property name="numHelperThreads">50</property>
        </named-config>
    
        <named-config name="littleTeenyApp">
            <property name="maxPoolSize">5</property>
            <property name="minPoolSize">2</property>
        </named-config>
    
    </c3p0-config>

    各用户(Per-user)配置

    你可以为某个特定用户已验证的池连接定义默认或命名配置的重写方法。并非所有的配置参数都支持各用户的方法重写。详情可见附录。

    你可以这样定义各用户配置:
    在属性类型的配置文件中:

    # define default-config param values
    c3p0.maxPoolSize=30
    c3p0.minPoolSize=10
    
    # define params for a user called 'steve'
    c3p0.user-overrides.steve.maxPoolSize=15
    c3p0.user-overrides.steve.minPoolSize=5
    
    # define params for a user called 'ramona'
    c3p0.user-overrides.steve.maxPoolSize=50
    c3p0.user-overrides.steve.minPoolSize=20

    在HOCON配置文件中:

    c3p0 {
        maxPoolSize=30
        minPoolSize=10
    
        user-overrides {
            steve {
                maxPoolSize=15
                minPoolSize=5
            }
            ramona {
                maxPoolSize=50
                minPoolSize=20
            }
        }
    }

    在XML配置文件中:

    <c3p0-config>
    
        <default-config>
    
            <property name="maxPoolSize">30</property>
            <property name="minPoolSize">10</property>
    
            <user-overrides user="steve">
                <property name="maxPoolSize">15</property>
                <property name="minPoolSize">5</property>
            </user-overrides>
    
            <user-overrides user="ramona">
                <property name="maxPoolSize">50</property>
                <property name="minPoolSize">20</property>
            </user-overrides>
    
        </default-config>
    
    </c3p0-config>

    用户配置扩展

    用户可以添加自定义的配置信息,通常是定制的ConnectionCustomizers行为。用户自定义的配置存储为一个包含了String键和值的Map,存储在以下配置参数中:

    这个扩展Map能像其他的配置参数一样通过编程来配置。不过,定义这个扩展Map的键和值有着特殊的配置文件支持:
    在属性类型的配置文件中:

    c3p0.extensions.initSql=SET SCHEMA 'foo'
    c3p0.extensions.timezone=PDT
    ...

    在HOCON配置文件中:

    c3p0 {
        extensions {
            initSql=SET SCHEMA 'foo'
            timezone=PDT
        }
    }

    在XML配置文件中:

    <c3p0-config>
        <default-config>
            <extensions>
                <property name="initSql">SET SCHEMA 'foo'</property>
                <property name="timezone">PDT</property>
            </extensions>
        </default-config>
    </c3p0-config>

    为了找到池化数据源的扩展定义,你必须获得它的identityToken权限,这在所有ConnectionCustomizer中都作为一个参数被提供。获得了identityToken权限,你就可以通过使用C3P0Registry.extensionsForToken(...)方法来获取扩展Map

    由于这些扩展主要被设计用于ConnectionCustomizer的实现,AbatractConnectionCustomizer类同样定义了一个protected extensionForToken(...)方法。

    下面是一个使用了用户自定义配置扩展的ConnectionCustomizer实现。它定义了一个initSql扩展,这个扩展的值应当是String类型的包含应当在Connection被池允许时执行的SQL语句。

    package mypkg;
    
    import java.sql.*;
    import com.mchange.v2.c3p0.AbstractConnectionCustomizer;
    
    public class InitSqlConnectionCustomizer extends AbstractConnectionCustomizer{
        private String getInitSql( String parentDataSourceIdentityToken ){
        return (String) extensionsForToken( parentDataSourceIdentityToken ).get ( "initSql" ); 
    }
    
        public void onCheckOut( Connection c, String parentDataSourceIdentityToken) throws Exception{
            String initSql = getInitSql( parentDataSourceIdentityToken );
            if ( initSql != null ){
                Statement stmt = null;
                try{
                    stmt = c.createStatement();
                    stmt.executeUpdate( initSql );
                }
                finally{ 
                    if ( stmt != null ) stmt.close(); 
                }
            }
        }
    }

    混合命名的、各用户的、用户定义的配置扩展

    命名配置、各用户重写以及用户自定义配置扩展可以很方便地结合起来:
    在属性类型的配置文件中:

    c3p0.maxPoolSize=30
    c3p0.extensions.initSql=SET SCHEMA 'default'
    
    c3p0.named-configs.intergalactoApp.maxPoolSize=1000
    c3p0.named-configs.intergalactoApp.extensions.initSql=SET SCHEMA 'intergalacto'
    c3p0.named-configs.user-overrides.steve.maxPoolSize=20

    在HOCON配置文件中:

    c3p0 {
        maxPoolSize=30
        extensions {
            initSql=SET SCHEMA 'default'
        }
        named-configs {
            intergalactoApp {
                maxPoolSize=1000
                user-overrides {
                    steve {
                        maxPoolSize=20
                    }
                }
                extensions {
                    initSql=SET SCHEMA 'intergalacto'
                }
            }
        }
    }

    在XML配置文件中:

    <c3p0-config>
    
        <default-config>
            <property name="maxPoolSize">30</property>
            <extensions>
                <property name="initSql">SET SCHEMA 'default'</property>
            </extensions>
        </default-config>
    
        <named-config name="intergalactoApp">
            <property name="maxPoolSize">1000</property>
            <user-overrides name="steve">
                <property name="maxPoolSize">20</property>
            </user-overrides>
            <extensions>
                <property name="initSql">SET SCHEMA 'intergalacto'</property>
            </extensions>
        </named-config>
    
    </c3p0-config>

    附录

    性能

    增强性能,是连接池、 Statement 池以及 c3p0 类库的主要目的。对大多数应用程序来说,连接池会使得性能显著提高,特别是当你给每个客户端访问每次都重新获取连接的话。 如果你让单个的共享的连接来为多个客户端服务以避免过多的连接获取工作的话,那么你在多线程的环境下可能会遇到性能或者事物管理问题;连接池将会能够让你有机会选择很少或没有开销的单客户端单连接模型(One Connection-per client model)。 如果你正在编写企业级 Java Bean,你可能会想要只获取一次连接然后并不返回它,直到它被销毁或者过时。 但是这样做太耗费资源了,因为这些 Bean 不必要的占用了连接网络和数据库资源。连接池允许 Bean只在使用连接时才占有连接。

    但是,c3p0 也有性能上的开销。为了实现当父资源返回池得时候自动清理未被关闭的
    ResultSetStatement,所有客户端可见的 ConnectionResultSetStatement 都封装了那些底层的数据源或者“传统的”JDBC 驱动。因此,所有 JDBC 调用都会有一些额外的开销。

    c3p0 在减小“封装”所带来的性能开销方面下了一些工夫。在我的环境中,由包装所带来的性能问题来自成百上千的数据库获取操作。所以,你应该从 c3p0 中得到的是性能的提升和高效的资源利用,除非你快速地轮载(succession)了很多很多 JDBC 调用。很显然,与结果集相关操作(比如要在其上遍历一个有上千条记录的表)带来的开销是可以忽略不计的。

    API

    API文档见:
    http://www.mchange.com/projects/c3p0/apidocs/index.html

    配置属性和配置文档

    <c3p0-config>
    <default-config>
    <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
    <property name="acquireIncrement">3</property>
    
    <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
    <property name="acquireRetryAttempts">30</property>
    
    <!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
    <property name="acquireRetryDelay">1000</property>
    
    <!--连接关闭时默认将所有未提交的操作回滚。Default: false -->
    <property name="autoCommitOnClose">false</property>
    
    <!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么
    属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试
    使用。Default: null-->
    <property name="automaticTestTable">Test</property>
    
    <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效
    保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
    获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
    <property name="breakAfterAcquireFailure">false</property>
    
    <!--当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出
    SQLException,如设为0则无限期等待。单位毫秒。Default: 0 -->
    <property name="checkoutTimeout">100</property>
    
    <!--通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。
    Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester-->
    <property name="connectionTesterClassName"></property>
    
    <!--指定c3p0 libraries的路径,如果(通常都是这样)在本地即可获得那么无需设置,默认null即可
    Default: null-->
    <property name="factoryClassLocation">null</property>
    
    <!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs.
    (文档原文)作者强烈建议不使用的一个属性-->
    <property name="forceIgnoreUnresolvedTransactions">false</property>
    
    <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
    <property name="idleConnectionTestPeriod">60</property>
    
    <!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
    <property name="initialPoolSize">3</property>
    
    <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
    <property name="maxIdleTime">60</property>
    
    <!--连接池中保留的最大连接数。Default: 15 -->
    <property name="maxPoolSize">15</property>
    
    <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements
    属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
    如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
    <property name="maxStatements">100</property>
    
    <!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->
    <property name="maxStatementsPerConnection"></property>
    
    <!--c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能
    通过多线程实现多个操作同时被执行。Default: 3-->
    <property name="numHelperThreads">3</property>
    
    <!--当用户调用getConnection()时使root用户成为去获取连接的用户。主要用于连接池连接非c3p0
    的数据源时。Default: null-->
    <property name="overrideDefaultUser">root</property>
    
    <!--与overrideDefaultUser参数对应使用的一个参数。Default: null-->
    <property name="overrideDefaultPassword">password</property>
    
    <!--密码。Default: null-->
    <property name="password"></property>
    
    <!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意:
    测试的表必须在初始数据源的时候就存在。Default: null-->
    <property name="preferredTestQuery">select id from test where id=1</property>
    
    <!--用户修改系统配置参数执行前最多等待300秒。Default: 300 -->
    <property name="propertyCycle">300</property>
    
    <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的
    时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
    等方法来提升连接测试的性能。Default: false -->
    <property name="testConnectionOnCheckout">false</property>
    
    <!--如果设为true那么在取得连接的同时将校验连接的有效性。Default: false -->
    <property name="testConnectionOnCheckin">true</property>
    
    <!--用户名。Default: null-->
    <property name="user">root</property>
    
    <!--早期的c3p0版本对JDBC接口采用动态反射代理。在早期版本用途广泛的情况下这个参数
    允许用户恢复到动态反射代理以解决不稳定的故障。最新的非反射代理更快并且已经开始
    广泛的被使用,所以这个参数未必有用。现在原先的动态反射与新的非反射代理同时受到
    支持,但今后可能的版本可能不支持动态反射代理。Default: false-->
    <property name="usesTraditionalReflectiveProxies">false</property>
    
    <property name="automaticTestTable">con_test</property>
    <property name="checkoutTimeout">30000</property>
    <property name="idleConnectionTestPeriod">30</property>
    <property name="initialPoolSize">10</property>
    <property name="maxIdleTime">30</property>
    <property name="maxPoolSize">25</property>
    <property name="minPoolSize">10</property>
    <property name="maxStatements">0</property>
    <user-overrides user="swaldman">
    </user-overrides>
    </default-config>
    <named-config name="dumbTestConfig">
    <property name="maxStatements">200</property>
    <user-overrides user="poop">
    <property name="maxStatements">300</property>
    </user-overrides>
    </named-config>
    </c3p0-config> 

    Hibernate相关

    Hibernate的C3P0ConnectionPtovider重命名了7个c3p0配置属性,如果你在Hibernate中设置了它们,将覆盖所有可能在c3p0.properties文件中的配置。

    c3p0本地属性名Hibernate配置键
    c3p0.acquireIncrementhibernate.c3p0.acquire_increment
    c3p0.idleConnectionTestPeriodhibernate.c3p0.idle_test_period
    c3p0.initialPoolSize未提供,使用最小值
    c3p0.maxIdleTimehibernate.c3p0.timeout
    c3p0.maxPoolSizehibernate.c3p0.max_size
    c3p0.maxStatementshibernate.c3p0.max_statements
    c3p0.minPoolSizehibernate.c3p0.min_size
    c3p0.testConnectionOnCheckouthibernate.c3p0.validate(仅用于Hibernate 2.x)

    你可以在Hibernate配置中使用hibernate.c3p0前缀来设置任何c3p0属性。例如:

    hibernate.c3p0.unreturnedConnectionTimeout=30
    hibernate.c3p0.debugUnreturnedConnectionStackTraces=true

    JBoss相关

    在JBoss中使用c3p0:

    1. 将c3p0的jar文件放到JBoss服务实例中的lib目录下(如:${JBOSS_HOME}/server/default/lib
    2. 在JBoss服务实例的deploy目录下(如:${JBOSS_HOME}/server/default/deploy)定义并保存c3p0-service.xml文件。参数必须大写:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE server>
    
    <server>
    
       <mbean code="com.mchange.v2.c3p0.jboss.C3P0PooledDataSource"
              name="jboss:service=C3P0PooledDataSource">
         
          <attribute name="JndiName">java:PooledDS</attribute>
          <attribute name="JdbcUrl">jdbc:postgresql://localhost/c3p0-test</attribute>
          <attribute name="DriverClass">org.postgresql.Driver</attribute>
          <attribute name="User">swaldman</attribute>
          <attribute name="Password">test</attribute>
    
          <!-- Uncomment and set any of the optional parameters below -->
          <!-- See c3p0's docs for more info.                         -->
    
          <!-- <attribute name="AcquireIncrement">3</attribute>                         -->
          <!-- <attribute name="AcquireRetryAttempts">30</attribute>                    -->
          <!-- <attribute name="AcquireRetryDelay">1000</attribute>                     -->
          <!-- <attribute name="AutoCommitOnClose">false</attribute>                    -->
          <!-- <attribute name="AutomaticTestTable"></attribute>                        -->
          <!-- <attribute name="BreakAfterAcquireFailure">false</attribute>             -->
          <!-- <attribute name="CheckoutTimeout">0</attribute>                          -->
          <!-- <attribute name="ConnectionCustomizerClassName"></attribute>             -->
          <!-- <attribute name="ConnectionTesterClassName"></attribute>                 -->
          <!-- <attribute name="Description">A pooled c3p0 DataSource</attribute>       -->
          <!-- <attribute name="DebugUnreturnedConnectionStackTraces">false</attribute> -->
          <!-- <attribute name="FactoryClassLocation"></attribute>                      -->
          <!-- <attribute name="ForceIgnoreUnresolvedTransactions">false</attribute>    -->
          <!-- <attribute name="IdleConnectionTestPeriod">0</attribute>                 -->
          <!-- <attribute name="InitialPoolSize">3</attribute>                          -->
          <!-- <attribute name="MaxAdministrativeTaskTime">0</attribute>                -->
          <!-- <attribute name="MaxConnectionAge">0</attribute>                         -->
          <!-- <attribute name="MaxIdleTime">0</attribute>                              -->
          <!-- <attribute name="MaxIdleTimeExcessConnections">0</attribute>             -->
          <!-- <attribute name="MaxPoolSize">15</attribute>                             -->
          <!-- <attribute name="MaxStatements">0</attribute>                            -->
          <!-- <attribute name="MaxStatementsPerConnection">0</attribute>               -->
          <!-- <attribute name="MinPoolSize">0</attribute>                              -->
          <!-- <attribute name="NumHelperThreads">3</attribute>                         -->
          <!-- <attribute name="PreferredTestQuery"></attribute>                        -->
          <!-- <attribute name="TestConnectionOnCheckin">false</attribute>              -->
          <!-- <attribute name="TestConnectionOnCheckout">false</attribute>             -->
          <!-- <attribute name="UnreturnedConnectionTimeout">0</attribute>              -->
          <!-- <attribute name="UsesTraditionalReflectiveProxies">false</attribute>     -->
    
          <depends>jboss:service=Naming</depends>
       </mbean>
    
    </server>

    Oracle相关

    Oracle JDBC驱动提供了一个非标准的API以创建临时BLOBCLOB,用户必须对原始的Oracle特定连接实例调用方法。进阶用户可能用如上描述原始的连接操作来实现这个功能,但在一个单独的jar文件(c3p0-oracle-thin-extras-0.95-pre8.jar)中,提供了一个方便的类。你可以查询com.mchange.v2.c3p0.dbms.OracleUtils中的API文档获取详细信息。

    Tomcat中部署c3p0

    在Apache的Tomcat网络应用服务中配置c3p0池数据源是很容易的。以下是一个Tomcat 5.0的案例,它是Tomcat中conf/server.xml文件中的一部分,应当被修改以适应置于<Context>元素中。

    <Resource name="jdbc/pooledDS" auth="Container" type="com.mchange.v2.c3p0.ComboPooledDataSource" />
    <ResourceParams name="jdbc/pooledDS">
      <parameter>
        <name>factory</name>
        <value>org.apache.naming.factory.BeanFactory</value>
      </parameter>
      <parameter>
        <name>driverClass</name>
        <value>org.postgresql.Driver</value>
      </parameter>
      <parameter>
        <name>jdbcUrl</name>
        <value>jdbc:postgresql://localhost/c3p0-test</value>
      </parameter>
      <parameter>
        <name>user</name>
        <value>swaldman</value>
      </parameter>
      <parameter>
        <name>password</name>
        <value>test</value>
      </parameter>
      <parameter>
        <name>minPoolSize</name>
        <value>5</value>
      </parameter>
      <parameter>
        <name>maxPoolSize</name>
        <value>15</value>
      </parameter>
      <parameter>
        <name>acquireIncrement</name>
        <value>5</value>
      </parameter>
    </ResourceParams>

    对于Tomcat 5.5,使用以下配置:

    <Resource auth="Container"
               description="DB Connection"
              driverClass="com.mysql.jdbc.Driver"
              maxPoolSize="4"
              minPoolSize="2"
              acquireIncrement="1"
              name="jdbc/TestDB"
              user="test"
              password="ready2go"
              factory="org.apache.naming.factory.BeanFactory"
              type="com.mchange.v2.c3p0.ComboPooledDataSource"
              jdbcUrl="jdbc:mysql://localhost:3306/test?autoReconnect=true" />

    下面是一个标准的J2EE配置:你必须在你的web.xml文件中声明你的数据源。

    <resource-ref>
      <res-ref-name>jdbc/pooledDS</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
    </resource-ref>

    然后你可以在你的网络应用中如下配置以访问你的数据源:

    InitialContext ic = new InitialContext();
    DataSource ds = (DataSource) ic.lookup("java:comp/env/jdbc/pooledDS");

    已知缺陷

    版权相关

    by Steve Waldman <swaldman@mchange.com>
    © 2014 Machinery For Change, Inc.
    This software is made available for use, modification, and redistribution, under the terms of the Lesser GNU Public License, v.2.1 (LGPL) or the Eclipse Public License, v.1.0 (EPL), at your option. You should have received copies of both licenses with this distribution.

    翻译:PSJay liuhuanting

    2015-06-01 17:31