• 开源数据库连接池之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 }
    View Code

      在上面的代码中,在该工具类一加载进内存时就利用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 }
    View Code

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

      

      红字信息是因为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>
    View Code

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

      

      ⑴ 如果想用默认配置,则在程序中只要在创建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>
    View Code

      在这个配置文件中,默认配置是使用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 }
    View Code

      在这个代码中,通过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 }
    View Code

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

      

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

     

    参考博客:

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

                      

  • 相关阅读:
    并发编程-协程
    并发编程--线程
    并发编程--进程
    并发编程--操作系统介绍
    套接字Socket
    网络基础
    异常处理
    面向对象-常用模块
    面向对象进阶(反射)
    C#项目优化
  • 原文地址:https://www.cnblogs.com/fjdingsd/p/5273136.html
Copyright © 2020-2023  润新知