開源數據庫連接池之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

 

 

 

 

                  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM