开源数据库连接池之C3P0
Posted fjdingsd
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了开源数据库连接池之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的一些信息:
这里面有一些很有帮助的文档,例如快速入门(QuickStart)等等,这里就简单介绍一下:
要使用C3P0同样需要下载其jar包,在C3P0的jar包中共有三个jar包,如下图所示:
如果使用的是非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包:
同前一篇博客一样,我们现在是使用数据库连接池来获取连接了,而不是通过数据库直接提供的连接,因此《JDBC操作数据库的学习(2)》中的数据库工具类JdbcUtils的部分方法已经不适用了,现在我们重新在刚建的工程中编写一个新的JdbcUtils工具类:
1 public class JdbcUtils {
2 private static ComboPooledDataSource ds = null;
3 static{
4 try {
5 ds = new ComboPooledDataSource();
6 ds.setDriverClass("com.mysql.jdbc.Driver"); //为C3P0配置MySQL数据库驱动
7 ds.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcdemo"); //为C3P0配置MySQL数据库URL
8 ds.setUser("root");
9 ds.setPassword("root");
10 ds.setMaxPoolSize(50); //设置连接池最大连接数
11 ds.setMinPoolSize(5); //设置连接池最小连接数
12 ds.setInitialPoolSize(10); //设置连接池初始化连接数
13
14 } catch (PropertyVetoException e) {
15 throw new ExceptionInInitializerError(e);
16 }
17 }
18
19 public static Connection getConnection() throws SQLException {
20 return ds.getConnection(); //使用ComboPooledDataSource对象获取连接
21 }
22
23 public static void release(Connection conn,Statement st,ResultSet rs) {
24 if(rs!=null) {
25 try{
26 rs.close();
27 }catch (Exception e) {
28 e.printStackTrace();
29 }
30 }
31 if(st!=null) {
32 try{
33 st.close();
34 }catch (Exception e) {
35 e.printStackTrace();
36 }
37 }
38 if(conn!=null) {
39 try{
40 conn.close();
41 }catch (Exception e) {
42 e.printStackTrace();
43 }
44 }
45 }
46 }
在上面的代码中,在该工具类一加载进内存时就利用C3P0的连接池类ComboPooledDataSource的对象来设置各个数据库驱动和连接池的参数,例如上面我们设置了数据库连接驱动、数据库URL、数据库用户名和密码、连接池里的最大和最小连接数,连接池初始化时的连接数等等,当然上面的配置只是ComboPooledDataSource对象中设置方法的冰山一角,我们还可以通过ComboPooledDataSource对象的方法为我们的连接池设置更多的功能和参数。
而我们要给别的想操作数据库的方法返回的连接即使通过ComboPooledDataSource对象的getConnection()方法取得的Connection对象,另外通过释放资源的方法还是和以前一模一样,尤其是调用了Connection对象的close方法就能知道,这个Connection对象必定经过C3P0进行功能增强,将数据库直接提供的Connection对象的close方法进行了覆写,才能使我们释放资源时(调用Connection对象的close方法)不会将连接销毁,而是重新放入C3P0的连接池中。
下面我们将通过一个测试代码来看看通过C3P0连接池获得的Connection对象:
1 public void testConnection() throws SQLException {
2 Connection conn = null;
3 PreparedStatement st = null;
4 ResultSet rs = null;
5
6 try{
7 conn = JdbcUtils.getConnection();
8 System.out.println(conn);
9 System.out.println(conn.getClass().getName());
10 }finally{
11 JdbcUtils.release(conn, st, rs);
12 }
13 }
在控制台上显示的效果如下:
红字信息是因为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)有如下配置参数:
在这张表的下面还有对每一个参数的各种介绍功能和一些默认值,这里就省略不贴图出来了。
接下来就是配置文件了,和DBCP不一样,C3P0必须使用XML来作为配置文件,而且配置文件名和应该放置的位置都有严格的规定:
首先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>
在官方给出的配置文件例子中,有默认配置和自定义配置两种:
⑴ 如果想用默认配置,则在程序中只要在创建ComboPooledDataSource对象时调用其无参的构造器即可,例如ComboPooledDataSource ds = new ComboPooledDataSource()即是使用默认配置。
⑵ 如果是想使用自定义配置,则在创建ComboPooledDataSource对象时将自定义配置的<named-config>指定的名称作为参数传进ComboPooledDataSource的构造器即可,例如按上图的例子来说ComboPooledDataSource ds = new ComboPooledDataSource(“intergalactoApp”)。因此这个配置文件可以配置多个自定义的参数内容,非常灵活,比如我们可以在一个C3P0配置文件中分别自定义MySQL数据库和Oracle数据库的配置参数。
现在我们开始真正地使用第二种方式来使用C3P0连接池,创建一个工程,因为我们使用的是MySQL数据库,因此只需要导入C3P0中的两个jar包即可,当然别忘了还有MySQL的数据库驱动jar包:
这回我们在【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,代码如下:
1 public class JdbcUtils {
2 private static ComboPooledDataSource ds = null;
3 static{
4 try {
5 ds = new ComboPooledDataSource(); //使用配置文件中的默认配置
6 // ds = new ComboPooledDataSource("oracle"); 如果要使用Oracle则使用配置文件中的自定义配置
7
8 } catch (Exception e) {
9 throw new ExceptionInInitializerError(e);
10 }
11 }
12
13 public static Connection getConnection() throws SQLException {
14 return ds.getConnection(); //使用ComboPooledDataSource对象获取连接
15 }
16
17 public static void release(Connection conn,Statement st,ResultSet rs) {
18 if(rs!=null) {
19 try{
20 rs.close();
21 }catch (Exception e) {
22 e.printStackTrace();
23 }
24 }
25 if(st!=null) {
26 try{
27 st.close();
28 }catch (Exception e) {
29 e.printStackTrace();
30 }
31 }
32 if(conn!=null) {
33 try{
34 conn.close();
35 }catch (Exception e) {
36 e.printStackTrace();
37 }
38 }
39 }
40 }
在这个代码中,通过ComboPooledDataSource获取C3P0的连接池对象,因为我们在创建该对象时没有在构造器中传入参数,因此使用的是默认配置,而我们在配置文件中的默认设置也就是使用MySQL数据库。
当然获取连接的getConnection方法和释放资源的release方法都还和例1 一样,通过连接池对象ComboPooledDataSource获取连接,而释放资源跟以前的代码没有任何区别,说明在释放资源调用Connection对象的close方法时,其实已经是被ComboPooledDataSource返回的另一种Connection对象覆写了close方法。
我们通过下面的代码再来试下通过配置文件的方式使用C3P0的连接好不好使:
1 public void testConnection() throws SQLException {
2 Connection conn = null;
3 PreparedStatement st = null;
4 ResultSet rs = null;
5
6 try{
7 conn = JdbcUtils.getConnection();
8 System.out.println(conn);
9 System.out.println(conn.getClass().getName());
10 }finally{
11 JdbcUtils.release(conn, st, rs);
12 }
13 }
在控制台效果如下,我们照样从C3P0连接池中获取到了连接:
以上就是我们对开源数据库连接池C3P0的整个学习和使用的过程。如果想对C3P0有更深入的理解,上面说过的文档可以是很好的学习方式。
参考博客:
http://weifly.iteye.com/blog/1227182
以上是关于开源数据库连接池之C3P0的主要内容,如果未能解决你的问题,请参考以下文章