【數據庫】--- 數據庫連接池的對比

轉載於:https://blog.csdn.net/fysuccess/article/details/66972554

1.數據庫連接池概述
數據庫連接的建立是一種耗時、性能低、代價高的操作,頻繁的數據庫連接的建立和關閉極大的影響了系統的性能。數據庫連接池是系統初始化過程中創建一定數量的數據庫連接放於連接池中,當程序需要訪問數據庫時,不再建立一個新的連接,而是從連接池中取出一個已建立的空閒連接,使用完畢後,程序將連接歸還到連接池中,供其他請求使用,從而實現的資源的共享,連接的建立、斷開都由連接池自身來管理。

數據庫連接池爲系統的運行帶來了以下優勢:昂貴的數據庫連接資源得到重用;減少了數據庫連接建立和釋放的時間開銷,提高了系統響應速度;統一的數據庫連接管理,避免了連接資源的泄露。

數據庫連接池運行機制:

系統初始化時創建連接池,程序操作數據庫時從連接池中獲取空閒連接,程序使用完畢將連接歸還到連接池中,系統退出時,斷開所有數據庫連接並釋放內存資源。

2.主流數據庫連接池比較
常用的主流開源數據庫連接池有C3P0、DBCP、Tomcat Jdbc Pool、BoneCP、Druid等

C3p0: 開源的JDBC連接池,實現了數據源和JNDI綁定,支持JDBC3規範和JDBC2的標準擴展。目前使用它的開源項目有Hibernate、Spring等。單線程,性能較差,適用於小型系統,代碼600KB左右。

DBCP (Database Connection Pool):由Apache開發的一個Java數據庫連接池項目, Jakarta commons-pool對象池機制,Tomcat使用的連接池組件就是DBCP。單獨使用dbcp需要3個包:common-dbcp.jar,common-pool.jar,common-collections.jar,預先將數據庫連接放在內存中,應用程序需要建立數據庫連接時直接到連接池中申請一個就行,用完再放回。單線程,併發量低,性能不好,適用於小型系統。

Tomcat Jdbc Pool:Tomcat在7.0以前都是使用common-dbcp做爲連接池組件,但是dbcp是單線程,爲保證線程安全會鎖整個連接池,性能較差,dbcp有超過60個類,也相對複雜。Tomcat從7.0開始引入了新增連接池模塊叫做Tomcat jdbc pool,基於Tomcat JULI,使用Tomcat日誌框架,完全兼容dbcp,通過異步方式獲取連接,支持高併發應用環境,超級簡單核心文件只有8個,支持JMX,支持XA Connection。

BoneCP:官方說法BoneCP是一個高效、免費、開源的Java數據庫連接池實現庫。設計初衷就是爲了提高數據庫連接池性能,根據某些測試數據顯示,BoneCP的速度是最快的,要比當時第二快速的連接池快25倍左右,完美集成到一些持久化產品如Hibernate和DataNucleus中。BoneCP特色:高度可擴展,快速;連接狀態切換的回調機制;允許直接訪問連接;自動化重置能力;JMX支持;懶加載能力;支持XML和屬性文件配置方式;較好的Java代碼組織,100%單元測試分支代碼覆蓋率;代碼40KB左右。

Druid:Druid是Java語言中最好的數據庫連接池,Druid能夠提供強大的監控和擴展功能,是一個可用於大數據實時查詢和分析的高容錯、高性能的開源分佈式系統,尤其是當發生代碼部署、機器故障以及其他產品系統遇到宕機等情況時,Druid仍能夠保持100%正常運行。主要特色:爲分析監控設計;快速的交互式查詢;高可用;可擴展;Druid是一個開源項目,源碼託管在github上。

主流連接池各項功能對比如下:

3.數據庫連接池Spring集成配置與JNDI配置
下面針對每一種連接池的使用方法,在開發中如何配置給出spring集成配置和在tomcat的conf/context.xml文件中配置2種方式,限於篇幅只給出基本參數,詳細參數可自行研究。

3.1 阿里Druid連接池
Maven依賴

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.0.28</version>
</dependency>

Spring集成配置方式

<!--Spring Druid 數據源配置-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 基本屬性 url、user、password -->
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="1" />
        <property name="minIdle" value="1" />
        <property name="maxActive" value="20" />
        <!-- 配置獲取連接等待超時的時間 -->
        <property name="maxWait" value="60000" />
        <!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <!-- 打開PSCache,並且指定每個連接上PSCache的大小 -->
        <property name="poolPreparedStatements" value="true" />
        <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
        <!-- 配置監控統計攔截的filters,去掉後監控界面sql無法統計 -->
        <property name="filters" value="stat" />
    </bean>
    Web.xml配置
     <!--druid WebStatFilter用於採集web-jdbc關聯監控的數據-->
      <filter>
        <filter-name>DruidWebStatFilter</filter-name>
        <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
        <init-param>
          <param-name>exclusions</param-name>
          <param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
        </init-param>
      </filter>
      <filter-mapping>
        <filter-name>DruidWebStatFilter</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>
      <!--druid訪問監控界面 /druid/index.html-->
      <servlet>
        <servlet-name>DruidStatView</servlet-name>
        <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>DruidStatView</servlet-name>
        <url-pattern>/druid/*</url-pattern>
      </servlet-mapping>

Tomcat中context.xml文件JNDI配置方式

com.alibaba.druid.pool.DruidDataSourceFactory實現了javax.naming.spi.ObjectFactory,可以作爲JNDI數據源來配置
<TOMCAT_HOME>/conf/context.xml配置JNDI方式

 <Resource
         name="jdbc/MysqlDataSource"
         factory="com.alibaba.druid.pool.DruidDataSourceFactory"
         auth="Container"
         type="javax.sql.DataSource"
         driverClassName="com.mysql.jdbc.Driver"
         url="jdbc:mysql://192.168.1.233:3306/lead_oams?useUnicode=true&characterEncoding=utf-8"
         username="lead_system"
         password="password"
         maxActive="50"
         maxWait="10000"
         removeabandoned="true"
         removeabandonedtimeout="60"
         logabandoned="false"
         filters="stat"/>
 web.xml配置
 <!--MySQL數據庫JNDI數據 -->
   <resource-ref>
       <description>MySQL DB Connection</description>
       <res-ref-name>jdbc/MysqlDataSource</res-ref-name>
       <res-type>javax.sql.DataSource</res-type>
       <res-auth>Container</res-auth>
   </resource-ref>
Java代碼中獲取JNDI數據源

  //1、初始化名稱查找上下文

  Context ctx =new InitialContext();

  //2、通過JNDI名稱找到DataSource

 DruidDataSource ds = (DruidDataSource)ctx.lookup("java:comp/env/jdbc/MysqlDataSource");

  //3、通過ds獲取數據庫連接對象

  Connectionconn = ds.getConnection();

3.2 BoneCP連接池
Maven依賴

<dependency>
  <groupId>com.jolbox</groupId>
  <artifactId>bonecp-spring</artifactId>
  <version>0.8.0.RELEASE</version>
</dependency>
Spring集成BoneCP配置方式

<!-- Spring BoneCP 數據源配置-->
    <bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
        <!-- 數據庫驅動 -->
        <property name="driverClass" value="${jdbc.driver}" />
        <!-- 相應驅動的jdbcUrl -->
        <property name="jdbcUrl" value="${jdbc.url}" />
        <!-- 數據庫的用戶名 -->
        <property name="username" value="${jdbc.username}" />
        <!-- 數據庫的密碼 -->
        <property name="password" value="${jdbc.password}" />
        <!-- 檢查數據庫連接池中空閒連接的間隔時間,單位是分,默認值:240,如果要取消則設置爲0 -->
        <property name="idleConnectionTestPeriod" value="60" />
        <!-- 連接池中未使用的鏈接最大存活時間,單位是分,默認值:60,如果要永遠存活設置爲0 -->
        <property name="idleMaxAge" value="30" />
        <!-- 每個分區最大的連接數 -->
        <property name="maxConnectionsPerPartition" value="150" />
        <!-- 每個分區最小的連接數 -->
        <property name="minConnectionsPerPartition" value="5" />
    </bean>
Tomcat中BoneCP使用JNDI配置方式

<Resource
  name="JNDIName"
  auth="Container"
  type="com.jolbox.bonecp.BoneCPDataSource"
  factory="org.apache.naming.factory.BeanFactory"
  driverClass="oracle.jdbc.driver.OracleDriver"
  username="root" 
    password="root" 
  jdbcUrl="jdbc:mysql://localhost:3306/test"
  idleConnectionTestPeriod="0"
  idleMaxAge="10"
  partitionCount="1"
  maxConnectionsPerPartition="5"
  minConnectionsPerPartition="1"
  connectionTestStatement=""
  initSQL="select 1 from dual"/>

Java代碼中獲取JNDI數據源

  //1、初始化名稱查找上下文

  Context ctx =new InitialContext();

  //2、通過JNDI名稱找到DataSource

  DataSource ds= (DataSource) ctx.lookup("java:comp/env/jdbc/MysqlDataSource");

  //3、通過ds獲取數據庫連接對象

  Connectionconn = ds.getConnection();

3.3 Tomcat Jdbc Pool連接池
Maven依賴

<dependency>
  <groupId>org.apache.tomcat</groupId>
  <artifactId>tomcat-jdbc</artifactId>
  <version>7.0.75</version>
</dependency>
<dependency>
  <groupId>org.apache.tomcat</groupId>
  <artifactId>tomcat-juli</artifactId>
  <version>7.0.75</version>
</dependency>
Spring集成Tomcat Jbdc Pool配置方式

<!--tomcat jdbc pool數據源配置--> 
    <bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
        <property name="poolProperties">
        <bean class="org.apache.tomcat.jdbc.pool.PoolProperties">
        <!--driverClassName url username password-->
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <!--jmx support-->
        <property name="jmxEnabled" value="true"/>
        <property name="testWhileIdle" value="true"/>
        <property name="testOnBorrow" value="true"/>
        <property name="testOnReturn" value="false"/>
        <property name="validationInterval" value="30000"/>
        <property name="validationQuery" value="SELECT 1"/>
        <property name="timeBetweenEvictionRunsMillis" value="30000"/>
        <!--最大連接-->
        <property name="maxActive" value="50"/>
        <!--初始化連接-->
        <property name="initialSize" value="5"/>
        <!--最長等待時間ms-->
        <property name="maxWait" value="10000"/>
        <property name="minEvictableIdleTimeMillis" value="30000"/>
        <property name="minIdle" value="10"/>
        <!--是否允許日誌-->
        <property name="logAbandoned" value="false"/>
        <property name="removeAbandoned" value="true"/>
        <property name="removeAbandonedTimeout" value="60"/>
        <property name="jdbcInterceptors" value="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"/>
    </bean>
Tomcat中context.xml文件JNDI配置方式

<Resource   
    name="jdbc/test"  
    auth="Container"  
    factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"  
    testWhileIdle="true"  
    testOnBorrow="true"  
    testOnReturn="false"  
    validationQuery="SELECT 1"  
    validationInterval="30000"  
    timeBetweenEvictionRunsMillis="30000"  
    driverClassName="com.mysql.jdbc.Driver"  
    maxActive="100"  
    maxIdle="40"
    maxWait="12000"  
    initialSize="10"  
    removeAbandonedTimeout="60"  
    removeAbandoned="true"  
    logAbandoned="true"  
    minEvictableIdleTimeMillis="30000"  
    jmxEnabled="true"  
    jdbcInterceptors=  
     "org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"  
    username="root" 
    password="root" 
    type="javax.sql.DataSource"   
    url="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8"/>      
Java代碼中獲取JNDI數據源

//1、初始化名稱查找上下文

  Context ctx =new InitialContext();

  //2、通過JNDI名稱找到DataSource

  DataSource ds= (DataSource) ctx.lookup("java:comp/env/jdbc/test");

  //3、通過ds獲取數據庫連接對象

  Connectionconn = ds.getConnection();

3.4 Apache DBCP連接池
Maven依賴

<dependency>
  <groupId>commons-dbcp</groupId>
  <artifactId>commons-dbcp</artifactId>
  <version>1.4</version>
</dependency>
<dependency>
  <groupId>commons-collections</groupId>
  <artifactId>commons-collections</artifactId>
  <version>3.2.2</version>
</dependency>
<dependency>
  <groupId>commons-pool</groupId>
  <artifactId>commons-pool</artifactId>
  <version>1.6</version>
</dependency>
Spring集成DBCP配置方式

 <!-- 配置dbcp數據源 -->
      <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <!-- 池啓動時創建的連接數量 -->
        <property name="initialSize" value="5"/>
        <!-- 同一時間可以從池分配的最多連接數量。設置爲0時表示無限制。 -->
        <property name="maxActive" value="50"/>
        <!-- 池裏不會被釋放的最多空閒連接數量。設置爲0時表示無限制。 -->
        <property name="maxIdle" value="10"/>
        <!-- 在不新建連接的條件下,池中保持空閒的最少連接數。 -->
        <property name="minIdle" value="3"/>
        <!-- 設置自動回收超時連接 -->  
        <property name="removeAbandoned" value="true" />
        <!-- 自動回收超時時間(以秒數爲單位) -->  
        <property name="removeAbandonedTimeout" value="200"/>
        <!-- 設置在自動回收超時連接的時候打印連接的超時錯誤  --> 
        <property name="logAbandoned" value="true"/>
        <!-- 等待超時以毫秒爲單位,在拋出異常之前,池等待連接被回收的最長時間(當沒有可用連接時)。設置爲-1表示無限等待。-->  
        <property name="maxWait" value="100"/>  
      </bean>
Tomcat中context.xml文件JNDI配置方式

<Resource name="/jdbc/test" 
        type="javax.sql.DataSource" 
        driverClassName="com.sybase.jdbc3.jdbc.SybDataSource" 
        url="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8" 
        username="root" 
        password="root" 
        initialSize="5"
        maxActive="50" 
        maxIdle="10" 
        minIdle="3"
        maxWait="50000" />    
Java代碼中獲取JNDI數據源

//1、初始化名稱查找上下文

  Context ctx =new InitialContext();

  //2、通過JNDI名稱找到DataSource

  DataSource ds= (DataSource) ctx.lookup("java:comp/env/jdbc/test");

  //3、通過ds獲取數據庫連接對象

  Connectionconn = ds.getConnection();

3.5 C3p0連接池
Maven依賴

<dependency>
  <groupId>c3p0</groupId>
  <artifactId>c3p0</artifactId>
  <version>0.9.1.2</version>
</dependency>
Spring集成配置方式

<!-- Spring配置c3p0數據源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="jdbcUrl" value="${jdbc.url}" />
        <property name="driverClass" value="${jdbc.driverClassName}" />
        <property name="user" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <!--連接池中保留的最大連接數。Default: 15 -->
        <property name="maxPoolSize" value="100" />
        <!--連接池中保留的最小連接數。-->
        <property name="minPoolSize" value="1" />
        <!--初始化時獲取的連接數,取值應在minPoolSize與maxPoolSize之間。Default: 3 -->
        <property name="initialPoolSize" value="10" />
        <!--最大空閒時間,60秒內未使用則連接被丟棄。若爲0則永不丟棄。Default: 0 -->
        <property name="maxIdleTime" value="30" />
        <!--當連接池中的連接耗盡的時候c3p0一次同時獲取的連接數。Default: 3 -->
        <property name="acquireIncrement" value="5" />
        <!--JDBC的標準參數,用以控制數據源內加載的PreparedStatements數量。Default: 0-->
        <property name="maxStatements" value="0" />
        <!--每60秒檢查所有連接池中的空閒連接。Default: 0 -->
        <property name="idleConnectionTestPeriod" value="60" />
        <!--定義在從數據庫獲取新連接失敗後重復嘗試的次數。Default: 30 -->
        <property name="acquireRetryAttempts" value="30" />
        <!--獲取連接失敗將會引起所有等待連接池來獲取連接的線程拋出異常。Default: false-->
        <property name="breakAfterAcquireFailure" value="true" />
        <!--因性能消耗大請只在需要的時候使用它。Default: false -->
        <property name="testConnectionOnCheckout"  value="false" />        
    </bean>

Tomcat中context.xml文件JNDI配置方式

 <Resource 
          name="jdbc/MysqlDataSource" 
          auth="Container"
          factory="org.apache.naming.factory.BeanFactory" 
          type="com.mchange.v2.c3p0.ComboPooledDataSource"
          driverClass="com.mysql.jdbc.Driver"
          idleConnectionTestPeriod="60"
         maxPoolSize="50" 
         minPoolSize="2"
         acquireIncrement="2" 
         user="root" 
         password="root"
         jdbcUrl="jdbc:mysql://localhost:3306/test"/>    
Java代碼中獲取JNDI數據源

  //1、初始化名稱查找上下文

  Context ctx =new InitialContext();

  //2、通過JNDI名稱找到DataSource

  DataSource ds= (DataSource) ctx.lookup("java:comp/env/jdbc/MysqlDataSource");

  //3、通過ds獲取數據庫連接對象

  Connectionconn = ds.getConnection();

4.總結
     本文所比較的5種數據庫連接池在性能方面,根據個人測試結果和參考網上資料Druid > TomcatJDBC > DBCP > C3P0,BoneCP的性能方面沒有深入比較,應該和Tomcat Jdbc差不多。對於小型的系統,併發壓力不大時,選擇哪一種數據庫連接池差別不會很大,主要考慮的應該是連接池的穩定性。當併發量較高時,一般不會選擇使用DBCP和C3P0,選擇Druid是較好的。本文給出了5種數據庫連接池通過Spring配置和Tomcat JNDI方式配置兩種方式,Spring配置一般使用單獨的屬性文件,每一個連接池都提供了使用代碼創建的方式,使用方式也比較類似,感興趣可以自行研究。另外連接不同的數據庫時,在配置方面的差異主要在driverClass和jdbcUrl兩項,優化配置項可以另行考慮。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章