开源数据库连接池之C3P0

  本篇介绍几种开源数据库连接池,同时重点讲述如何使用C3P0数据库连接池。

  之前的博客已经重点讲述了使用数据库连接池的好处,即是将多次创建连接转变为一次创建而使用长连接模式。这样能减少数据库创建连接的消耗。正是由于数据库连接池的思想非常重要,所以市面上也有很多开源的数据库连接池供我们使用。主要有以下三个:

  DBCP数据库连接池

  C3P0 数据库连接池

  Tomcat内置的数据库连接池(DBCP)

  本篇主要讲述C3P0数据库连接池的使用,关于另外两个数据库连接池的用法请看《开源数据库连接池之DBCP》 、《开源数据库连接池之Tomcat内置连接池》 。如果我们使用这些开源的数据库连接池,我们就可以省略像前一篇博客中自己创建数据库连接池的步骤,这样会省略我们很多事。

  C3P0的官网是http://sourceforge.net/projects/c3p0/?source=navbar ,比较不好找。

  C3P0实现了连接池和JNDI的绑定,支持JDBC3规范和JDBC2的标准扩展。C3P0与DBCP的区别在于DBCP没有自动回收空闲连接的功能,而C3P0却有。但是C3P0在从连接池中获取和返回连接对象的时候,采用了异步处理方式(即非线程安全,关于异步可以看这篇很好的文章http://www.cnblogs.com/xiohao/p/4385508.html )。

  要想了解更多关于C3P0概念的信息,可以通过下载的C3P0的包中的【doc】目录下的index.html来查看关于C3P0的一些信息:

  开源数据库连接池之C3P0

这里面有一些很有帮助的文档,例如快速入门(QuickStart)等等,这里就简单介绍一下:

  开源数据库连接池之C3P0

要使用C3P0同样需要下载其jar包,在C3P0的jar包*有三个jar包,如下图所示:

  开源数据库连接池之C3P0

  如果使用的是非Oracle数据库,则只需导入c3p0-0.9.5.2jar包和mechange-commons-java-0.2.11.jar包即可,如果是使用Oracle数据库的话,还需要导入c3p0-oracle-thin-extras-0.9.5.2.jar包。

  C3P0可以有两种使用方法,一种是直接在程序中以调用ComboPooledDataSource对象的一系列方法配置各种数据库和连接池的参数,另一种也是跟DBCP一样使用配置文件来初始化数据库和连接池。

例1:使用第一种方式来简单创建C3P0数据库连接池

  在本例中我们仅使用C3P0的连接池类ComboPooledDataSource的对象来设置各个数据库驱动和连接池的参数,这种方法无需配置文件,换句话说也就是在程序中“写死”各个配置信息。

创建一个工程,因为我们使用的是MySQL数据库,因此只需要导入C3P0中的两个jar包即可,当然别忘了还有MySQL的数据库驱动jar包:

  开源数据库连接池之C3P0

  同前一篇博客一样,我们现在是使用数据库连接池来获取连接了,而不是通过数据库直接提供的连接,因此《JDBC操作数据库的学习(2)》中的数据库工具类JdbcUtils的部分方法已经不适用了,现在我们重新在刚建的工程中编写一个新的JdbcUtils工具类:

 public class JdbcUtils {
private static ComboPooledDataSource ds = null;
static{
try {
ds = new ComboPooledDataSource();
ds.setDriverClass("com.mysql.jdbc.Driver"); //为C3P0配置MySQL数据库驱动
ds.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcdemo"); //为C3P0配置MySQL数据库URL
ds.setUser("root");
ds.setPassword("root");
ds.setMaxPoolSize(50); //设置连接池最大连接数
ds.setMinPoolSize(5); //设置连接池最小连接数
ds.setInitialPoolSize(10); //设置连接池初始化连接数 } catch (PropertyVetoException e) {
throw new ExceptionInInitializerError(e);
}
} public static Connection getConnection() throws SQLException {
return ds.getConnection(); //使用ComboPooledDataSource对象获取连接
} public static void release(Connection conn,Statement st,ResultSet rs) {
if(rs!=null) {
try{
rs.close();
}catch (Exception e) {
e.printStackTrace();
}
}
if(st!=null) {
try{
st.close();
}catch (Exception e) {
e.printStackTrace();
}
}
if(conn!=null) {
try{
conn.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
}

  在上面的代码中,在该工具类一加载进内存时就利用C3P0的连接池类ComboPooledDataSource的对象来设置各个数据库驱动和连接池的参数,例如上面我们设置了数据库连接驱动、数据库URL、数据库用户名和密码、连接池里的最大和最小连接数,连接池初始化时的连接数等等,当然上面的配置只是ComboPooledDataSource对象中设置方法的冰山一角,我们还可以通过ComboPooledDataSource对象的方法为我们的连接池设置更多的功能和参数。

  而我们要给别的想操作数据库的方法返回的连接即使通过ComboPooledDataSource对象的getConnection()方法取得的Connection对象,另外通过释放资源的方法还是和以前一模一样,尤其是调用了Connection对象的close方法就能知道,这个Connection对象必定经过C3P0进行功能增强,将数据库直接提供的Connection对象的close方法进行了覆写,才能使我们释放资源时(调用Connection对象的close方法)不会将连接销毁,而是重新放入C3P0的连接池中。

  下面我们将通过一个测试代码来看看通过C3P0连接池获得的Connection对象:

 public void testConnection() throws SQLException {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null; try{
conn = JdbcUtils.getConnection();
System.out.println(conn);
System.out.println(conn.getClass().getName());
}finally{
JdbcUtils.release(conn, st, rs);
}
}

在控制台上显示的效果如下:

  开源数据库连接池之C3P0

  红字信息是因为C3P0在创建数据库连接池时会通过日志来记录其工作的一些信息,我们也可以通过这个信息来查看C3P0创建的连接池的情况。

  最后两行是我们通过上面的测试代码打印出来的Connection对象的信息,可以看到C3P0也将数据库驱动直接提供的Connection对象进行了功能增强,而这种增强方式是通过动态代理方式来覆写了原来Connection对象的close方法再返回给我们的,以使我们在释放资源时能将连接重新返回到C3P0的连接池中。

例2:使用第二种方式来简单创建C3P0数据库连接池

  和第一种方式不同,在本例中我们使用配置文件的方式使C3P0能配置我们的数据库驱动和连接池所需要的参数。这种方式的好处就是不会在程序里将这些参数“写死”。

  C3P0的配置文件里使用什么参数关键字呢?配置文件有没特殊的命名方式呢?配置文件需要放置在什么特别的地方吗?这三个问题是使用C3P0连接池第二种方式必须要知道的。

  先说配置文件里使用的参数关键字,这个可以由ComboPooledDataSource对象中的各种set方法得到,比如这个对象中的setDriverClass方法,那么使用配置文件的话配置数据库驱动类的参数即为driverClass。另一种参看C3P0配置参数的方式就是看上面曾经说过的C3P0的包中【doc】目录下的index.html文档,在这个文档找到附录B(Appendix B:Configuration Files)有如下配置参数:

  开源数据库连接池之C3P0

  在这张表的下面还有对每一个参数的各种介绍功能和一些默认值,这里就省略不贴图出来了。

  接下来就是配置文件了,和DBCP不一样,C3P0必须使用XML来作为配置文件,而且配置文件名和应该放置的位置都有严格的规定:

  开源数据库连接池之C3P0

  首先C3P0的配置文件必须要叫“c3p0-config.xml”,另外根据文档,这个配置文件必须要直接或者以jar包的形式存放在你应用的CLASSPATH路径或者WEB-INF/classes路径(WEB工程)下才行。当然我们知道在MyEclipse上如果将配置文件放在【src】目录中在IED编译运行时会自动将【src】中的文件放置在CLASSPATH路径中,所以我们可以直接将配置文件放在【src】目录里。

  而文档也提供了一个配置文件中参数内容的例子:

<c3p0-config>
<default-config>
<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">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property> <user-overrides user="test-user">
<property name="maxPoolSize">10</property>
<property name="minPoolSize">1</property>
<property name="maxStatements">0</property>
</user-overrides> </default-config> <!-- This app is massive! -->
<named-config name="intergalactoApp">
<property name="acquireIncrement">50</property>
<property name="initialPoolSize">100</property>
<property name="minPoolSize">50</property>
<property name="maxPoolSize">1000</property> <!-- intergalactoApp adopts a different approach to configuring statement caching -->
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property> <!-- he's important, but there's only one of him -->
<user-overrides user="master-of-the-universe">
<property name="acquireIncrement">1</property>
<property name="initialPoolSize">1</property>
<property name="minPoolSize">1</property>
<property name="maxPoolSize">5</property>
<property name="maxStatementsPerConnection">50</property>
</user-overrides>
</named-config>
</c3p0-config>

  在官方给出的配置文件例子中,有默认配置和自定义配置两种:

  开源数据库连接池之C3P0

  ⑴ 如果想用默认配置,则在程序中只要在创建ComboPooledDataSource对象时调用其无参的构造器即可,例如ComboPooledDataSource ds = new ComboPooledDataSource()即是使用默认配置。

  ⑵ 如果是想使用自定义配置,则在创建ComboPooledDataSource对象时将自定义配置的<named-config>指定的名称作为参数传进ComboPooledDataSource的构造器即可,例如按上图的例子来说ComboPooledDataSource ds = new ComboPooledDataSource(“intergalactoApp”)。因此这个配置文件可以配置多个自定义的参数内容,非常灵活,比如我们可以在一个C3P0配置文件中分别自定义MySQL数据库和Oracle数据库的配置参数。

  现在我们开始真正地使用第二种方式来使用C3P0连接池,创建一个工程,因为我们使用的是MySQL数据库,因此只需要导入C3P0中的两个jar包即可,当然别忘了还有MySQL的数据库驱动jar包:

  开源数据库连接池之C3P0

  这回我们在【src】目录中放置C3P0的配置文件c3p0-config.xml,内容以文档案例做了修改如下:

<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcdemo</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">50</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config> <!-- if you want to use Oracle database -->
<named-config name="oracle">
<property name="driverClass">oracle.jdbc.driver.OracleDriver</property>
<property name="jdbcUrl"> jdbc:oracle:thin:@localhost:1521:jdbcdemo</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">50</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</named-config>
</c3p0-config>

  在这个配置文件中,默认配置是使用MySQL数据库,也设置了一个自定义配置可以使用Oracle数据库。

  同例1一样,我们也是要改写以前的数据库工具类JdbcUtils,代码如下:

 public class JdbcUtils {
private static ComboPooledDataSource ds = null;
static{
try {
ds = new ComboPooledDataSource(); //使用配置文件中的默认配置
// ds = new ComboPooledDataSource("oracle"); 如果要使用Oracle则使用配置文件中的自定义配置 } catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
} public static Connection getConnection() throws SQLException {
return ds.getConnection(); //使用ComboPooledDataSource对象获取连接
} public static void release(Connection conn,Statement st,ResultSet rs) {
if(rs!=null) {
try{
rs.close();
}catch (Exception e) {
e.printStackTrace();
}
}
if(st!=null) {
try{
st.close();
}catch (Exception e) {
e.printStackTrace();
}
}
if(conn!=null) {
try{
conn.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
}

  在这个代码中,通过ComboPooledDataSource获取C3P0的连接池对象,因为我们在创建该对象时没有在构造器中传入参数,因此使用的是默认配置,而我们在配置文件中的默认设置也就是使用MySQL数据库。

  当然获取连接的getConnection方法和释放资源的release方法都还和例1 一样,通过连接池对象ComboPooledDataSource获取连接,而释放资源跟以前的代码没有任何区别,说明在释放资源调用Connection对象的close方法时,其实已经是被ComboPooledDataSource返回的另一种Connection对象覆写了close方法。

  我们通过下面的代码再来试下通过配置文件的方式使用C3P0的连接好不好使:

 public void testConnection() throws SQLException {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null; try{
conn = JdbcUtils.getConnection();
System.out.println(conn);
System.out.println(conn.getClass().getName());
}finally{
JdbcUtils.release(conn, st, rs);
}
}

  在控制台效果如下,我们照样从C3P0连接池中获取到了连接:

  开源数据库连接池之C3P0

  以上就是我们对开源数据库连接池C3P0的整个学习和使用的过程。如果想对C3P0有更深入的理解,上面说过的文档可以是很好的学习方式。

参考博客:

http://weifly.iteye.com/blog/1227182

上一篇:属性文件Plist


下一篇:Spring-表达式语言