1. 程式人生 > >資料庫連線池優缺點詳解

資料庫連線池優缺點詳解

一、訪問資料庫原因
在java程式中,需要訪問資料庫,做增刪改查等相關操作。如何訪問資料庫,做資料庫的相關操作呢? 
二、Java連線資料庫方法概述 
java.sql提供了一些介面和類,用於支援資料庫增刪改查等相關的操作。該jar包定義了java訪問各種不同資料庫(mysql,oracle,sqlserver。。。。。)的統一介面和標準。同時,各個資料庫廠商都提供了該jar包中定義的各個介面的實現類,用於具體實現本廠資料庫的增刪改查操作,即稱之為“資料庫驅動jdbc driver”。例如mysql的資料庫驅動為:com.mysql.jdbc.driver;oracle的資料庫驅動為:oracle.jdbc.driver.oracledriver。 
在java程式中訪問資料庫,做資料庫連線時,可以採用兩種方式: 
1、使用java.sql API 
利用該包提供的各種介面和類直接訪問資料庫。 
2、使用資料庫連線池 
目前存在多個開源的java資料庫連線池,這些連線池都是在java.sql基礎上編寫而成。 
?  該連線池的解決的問題是: 
當使用java.sql中提供的api建立資料庫連線時候,需要耗費很大的資源,要進行使用者名稱密碼資料庫連線驗證等,即耗費資源也耗費時間。如果在程式中,每次需要訪問資料庫時候,都進行資料庫連線,那麼勢必會造成效能低下;同時,如果使用者失誤忘記釋放資料庫連線,會導致資源的浪費等。而資料庫連線池就是解決該問題,通過管理連線池中的多個連線物件(connection),實現connection重複利用。從而,大大提高了資料庫連線方面的效能。 
?  該連線池的功能是: 
負責建立,管理,釋放,分配資料庫連線即(connection)。首先,負責建立相應數目的資料庫連線物件(connection)物件,並存放到資料庫連線池(connect pool)中。當用戶請求資料庫連線時,該連線池負責分配某個處於空閒狀態的資料庫連線物件;當用戶發出釋放該資料庫連線時,該連線池負責將該連線物件重新設定為空閒狀態,以便被別的請求重複利用。同時;資料庫連線池負責檢查(空閒時間>最大空閒時間)的資料庫連線,並釋放。 
?  連線池主要引數介紹 
最小連線數:初始化時,系統將負責建立該數目的connection放入連線池中。 
最大連線數:系統允許建立connection的最大數值。當系統請求連線時候,且連線池中不存在空閒的連線:如果connection總數未超過最大連線數,那麼連線池負責建立新的connection物件,並返回該物件;如果connection總數已經到達該最大連線數,那麼連線池將使用者請求轉入等待佇列。 
三、常用的資料庫連線池 

1、 JNDI 
2、 C3p0 
3、 Apache 的Jakarta DBCP 
4、 BoneCP 
其中,sping框架依賴的第三方使用了c3p0和dbcp兩種方式;而bonecp號稱是速度最快的資料庫連線池。JNDI方式建立實現的datasource是真正實現了javax.sql.datasource;其他的三種方式都不是。下面的列表,列出了幾種方式的區別和不同: 
序號 
連線池名稱 
依賴的jar包 
實現的datasource類 
備註 

JNDI 
該資料來源是由相應的web伺服器(例如:tomcat,weblogic,websphere)負責初始化,建立,管理。程式中不需要引入特別的jar包。 
Javax.sql.datasource 



C3P0 
c3p0-0.9.xxx.jar 
com.mchange.v2.c3p0.ComboPooledDataSource 



DBCP 
commons-dbcp.jar,commons-pool.jar 
org.apache.commons.dbcp.BasicDataSource 



BoneCP 


bonecp-0.6.5.jar 
· google-collections-1.0.jar 
· slf4j-api-1.5.11.jar 
· slf4j-log4j12-1.5.11.jar 
·log4j-1.2.15.jar 


BoneCPDataSource 


備註:以上幾種方式的資料庫連線池的配置引數大同小異,略有差別;其引數的配置,既可以通過配置檔案的方式配置,也可以通過硬編碼的方式配置。 


四、分別列出幾種連線池的編碼例子 

(所有的例子均可以參考D:\work\qsyworkspace2\jdbctest專案) 
1、 使用java.sql API直接訪問資料庫 
詳細請參考javasql.java檔案。 
       
Class.forName("com.mysql.jdbc.Driver"); 
           String url="jdbc:mysql://localhost:3306/editortest"; 
           String user="root"; 
           String password="123456"; 
           Connection cn=DriverManager.getConnection(url, user, password); 
           Statement st=cn.createStatement(); 
           String sql="select * from artical where id=1"; 
           ResultSet rs=st.executeQuery(sql); 
           while(rs.next()){ 
              System.out.println("1:"+rs.getString(1)); 
              System.out.println("2:"+rs.getString(2)); 
              System.out.println("3:"+rs.getString(3)); 
              System.out.println("4:"+rs.getString(4));    
        } 
2、 使用JNDI方式 
這種方式,是由web伺服器,實現了java.sql.datasource。由web伺服器負責初始化資料來源,建立connection,分配,管理connection。由於本身是由web伺服器實現的功能,因此不需要在專案project中引入特別的jar包,但是需要在伺服器的某些配置檔案中增加相關的配置。下面,以tomcat伺服器為例,講述這種方式的使用。 
    (1)、修改tomcat的conf下的context.xml檔案,增加Resource的配置的支援。 
    (2)、由於資料來源是由tomcat負責建立,所以需要的jdbc驅動應該放到tomcat的lib路徑下。 
    (3)、編寫使用java程式碼,並放在tomcat環境下使用,如下: 
public void jnditest(){ 
       // TODO Auto-generated method stub 
       try { 
           Context initcontext=new InitialContext(); 
           Context context=(Context) initcontext.lookup("java:comp/env"); 
          


           DataSource datasource=(DataSource)context.lookup("jdbc/editortest"); 
          
           Connection cn=datasource.getConnection(); 
          
           Statement st=cn.createStatement(); 
           String sql="select * from artical where id=1"; 
           ResultSet rs=st.executeQuery(sql); 
           while(rs.next()){ 
              System.out.println("1:"+rs.getString(1)); 
              System.out.println("2:"+rs.getString(2)); 
              System.out.println("3:"+rs.getString(3)); 
              System.out.println("4:"+rs.getString(4));    
           } 
       } catch (NamingException e) { 
           // TODO Auto-generated catch block 
           e.printStackTrace(); 
       } catch (SQLException e) { 
           // TODO Auto-generated catch block 
           e.printStackTrace(); 
       } 
    } 


        (4)、詳情參考jndisql。Java檔案,以及index.jsp。 


注意:該測試不能在main方法中測試;可以寫一個jsp在tomcat環境中測試。因為:java單元的環境是jdk;而jsp的環境卻是tomcat;資料連線池是在tomcat中配置的,所以能正常執行的,但java測試的環境只有jdk,所以在引用資料連線池時就時出現找不到環境的錯誤。 
使用環境:當使用weblogic或者websphere等高階的web伺服器的時候,可以考慮使用這種方式提高效能。 
3、 使用C3p0方式 
C3P0是開源的資料庫連線元件,支援建立資料庫連線池,管理connection等功能。使用該種方式做資料庫連線時候,需要匯入c3p0-0.9.1.2.jar。 
同時,關於資料庫連線的具體引數,例如:url,username,password,最小連線數,最大連線數。。。。。等資訊既可以在xml配置檔案中配置,也可以通過程式編碼方式建立。Spring支援c3p0的資料庫連線池方式,因此在spring環境中使用時,支援在applicationcontext.xml檔案中配置。另外,由於資料庫連線池在整個project中針對某個資料庫而言是單例的,所以,即使通過編碼的方式建立,那麼要保證其單例項特性。如果存在多個,那麼必然會導致效能低下。 
下面,列出通過程式編碼方式使用c3p0資料庫連線池的方式。 
ComboPooledDataSource ds = new ComboPooledDataSource(); 
       try { 
           ds.setDriverClass("com.mysql.jdbc.Driver"); 
           ds.setJdbcUrl("jdbc:mysql://localhost:3306/editortest"); 
           ds.setUser("root"); 
           ds.setPassword("123456"); 
           ds.setMaxPoolSize(20); 
           ds.setInitialPoolSize(10); 
           ds.setMaxIdleTime(2000); 
           Connection cn=ds.getConnection(); 
           Statement st=cn.createStatement(); 
           String sql="select * from artical where id=1"; 
           ResultSet rs=st.executeQuery(sql); 
           while(rs.next()){ 
              System.out.println("1:"+rs.getString(1)); 
               System.out.println("2:"+rs.getString(2)); 
              System.out.println("3:"+rs.getString(3)); 
              System.out.println("4:"+rs.getString(4));    
           } 
          
       } catch (PropertyVetoException e) { 
           // TODO Auto-generated catch block 
           e.printStackTrace(); 
       } catch (SQLException e) { 
           // TODO Auto-generated catch block 
           e.printStackTrace(); 
    } 
    備註:通常使用方式,都是通過配置檔案配置,幾乎不會用到這種硬編碼方式。在此,只是簡單介紹C3P0的使用方式。詳情,可以參考c3p0test.java。 
4、 使用dbcp方式 
DBCP方式,是apache提供的資料來源連線池方式,支援資料庫連線池建立,管理connection等功能。使用環境,需要匯入commons-dbcp.jar 和 commons-pool.jar兩個jar包。上面提到的JNDI方式,其實質實用的就是dbcp資料來源;只是他是通過在web伺服器上做配置,由web伺服器負責建立該資料來源。 
同樣的,dbcp資料來源也支援xml配置檔案和硬編碼兩種方式。通常使用方式,都是通過配置檔案配置,幾乎不會使用硬編碼方式。下面簡單介紹dbcp方式的編碼: 
BasicDataSource ds = new BasicDataSource(); 
       ds.setDriverClassName("com.mysql.jdbc.Driver"); 
       ds.setUrl("jdbc:mysql://localhost:3306/editortest"); 
       ds.setUsername("root"); 
       ds.setPassword("123456"); 
       ds.setMaxIdle(20); 
       ds.setInitialSize(10); 
       ds.setMaxActive(2000); 
       try { 
           Connection cn=ds.getConnection(); 
           Statement st=cn.createStatement(); 
           String sql="select * from artical where id=1"; 
           ResultSet rs=st.executeQuery(sql); 
           while(rs.next()){ 
              System.out.println("1:"+rs.getString(1)); 
              System.out.println("2:"+rs.getString(2)); 
              System.out.println("3:"+rs.getString(3)); 
              System.out.println("4:"+rs.getString(4));    
           } 
       } catch (SQLException e) { 
           // TODO Auto-generated catch block 
           e.printStackTrace(); 
    } 
5、 使用BoneCP方式。 
BoneCP是快速高效的資料庫連線池元件,據說效能上目前是最好得,比C3P0和DBCP快25倍。使用該元件,需要匯入bonecp-0.6.5.jar,google-collections-1.0.jar,slf4j-api-1.5.11.jar,slf4j-log4j12-1.5.11.jar,log4j-1.2.15.jar。 
下面,簡單列出編碼方式的使用,做簡單的瞭解。 
BoneCPDataSource ds = new BoneCPDataSource(); 
       ds.setDriverClass("com.mysql.jdbc.Driver"); 
       ds.setJdbcUrl("jdbc:mysql://localhost:3306/editortest"); 
       ds.setUsername("root"); 
       ds.setPassword("123456"); 
      
       try { 
           Connection cn = ds.getConnection(); 
           Statement st = cn.createStatement(); 
           String sql = "select * from artical where id=1"; 
           ResultSet rs = st.executeQuery(sql); 
           while (rs.next()) { 
              System.out.println("1:" + rs.getString(1)); 
              System.out.println("2:" + rs.getString(2)); 
               System.out.println("3:" + rs.getString(3)); 
              System.out.println("4:" + rs.getString(4)); 
           } 
       } catch (SQLException e) { 
           // TODO Auto-generated catch block 
           e.printStackTrace(); 
    } 


總結:以上,介紹了幾種常用的資料來源連線池;這幾種連線池在使用過程,即支援硬編碼的方式,也支援配置檔案的配置方式;在正式實用的時候,應該儘量使用配置的方式,便於維護和管理。硬編碼的方式,可以做為測試使用。同時,spring框架,通過他自己的方式整合上述幾種資料來源,理論上來說,都支援。各個資料來源連線池都有一些公有的屬性,因為他們都是從javax.sql.datasource繼承而來,而且都有最大連線數,初始化連線數等概念。同時,他們又分別有各自不同的屬性,做了擴充套件。這裡只是簡單的介紹,在實際使用中,想要實現高效能的資料庫連線池管理,還需要深入研究每種方式的連線屬性配置;例如:根據實際需要,設定合適的最小連線數和最大連線數,等待時間等。 


五、Java(x).sql直接操作資料庫與各個開源資料來源(datasource)關係 

當使用JDK提供的java(x).sql包中的類訪問資料庫時候,基本上用到的就是drivermanager,connection,statement,resultset。其中drivermanger是類,他呼叫相應的驅動(即各個資料庫廠商提供的驅動)中的方法生成connection物件。Connection是介面,在各個資料庫廠商提供的資料庫驅動中,都實現了該介面。例如:當使用com.mysql.jdbc.driver時候,生成的connection即為com.mysql.jdbc.Connection物件。 
Javax.sql包中定義了介面datasource,統一規定了作為資料來源連線池必須提供的方法和屬性等。各個資料來源元件中提供的datasource都實現了該介面。當通過資料來源連線池的方式獲取connnection的時候,同樣的,各個資料來源元件也都提供(實現了java.sql.connection)介面的類。 
更為具體的細節,可以參考jdk文件中關於java(x).sql包中相關類和介面的描述;參考開源資料來源連線池元件的相關原始碼(例如C3P0);參考相關的資料庫驅動。 


六、附錄:Java開源的資料庫連線池 
        在Java中開源的資料庫連線池有以下幾種 : 
  1, C3P0 C3P0是一個開放原始碼的JDBC連線池,它在lib目錄中與Hibernate一起釋出,包括了實現jdbc3和jdbc2擴充套件規範說明的Connection 和Statement 池的DataSources 物件。 
  2,Proxool 這是一個Java SQL Driver驅動程式,提供了對你選擇的其它型別的驅動程式的連線池封裝。可以非常簡單的移植到現存的程式碼中。完全可配置。快速,成熟,健壯。可以透明地為你現存的JDBC驅動程式增加連線池功能。 
  3,Jakarta DBCP DBCP是一個依賴Jakarta commons-pool物件池機制的資料庫連線池.DBCP可以直接的在應用程式用使用。 
  4,DDConnectionBroker DDConnectionBroker是一個簡單,輕量級的資料庫連線池。 
  5,DBPool DBPool是一個高效的易配置的資料庫連線池。它除了支援連線池應有的功能之外,還包括了一個物件池使你能夠開發一個滿足自已需求的資料庫連線池。 
  6,XAPool XAPool是一個XA資料庫連線池。它實現了javax.sql.XADataSource並提供了連線池工具。 
  7,Primrose Primrose是一個Java開發的資料庫連線池。當前支援的容器包括Tomcat4&5,Resin3與JBoss3.它同樣也有一個獨立的版本可以在應用程式中使用而不必執行在容器中。Primrose通過一個web介面來控制SQL處理的追蹤,配置,動態池管理。在重負荷的情況下可進行連線請求佇列處理。 
  8,SmartPool SmartPool是一個連線池元件,它模仿應用伺服器物件池的特性。SmartPool能夠解決一些臨界問題如連線洩漏(connection leaks),連線阻塞,開啟的JDBC物件如Statements,PreparedStatements等. SmartPool的特性包括支援多個pools,自動關閉相關聯的JDBC物件, 在所設定time-outs之後察覺連線洩漏,追蹤連線使用情況, 強制啟用最近最少用到的連線,把SmartPool"包裝"成現存的一個pool等。 
  9,MiniConnectionPoolManager MiniConnectionPoolManager是一個輕量級JDBC資料庫連線池。它只需要Java1.5(或更高)並且沒有依賴第三方包。 
10,BoneCP BoneCP是一個快速,開源的資料庫連線池。幫你管理資料連線讓你的應用程式能更快速地訪問資料庫。比C3P0/DBCP連線池快25倍