溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

在Spring中使用數(shù)據(jù)源DBCP、C3P0、JNDI的示例

發(fā)布時(shí)間:2021-02-07 10:39:21 來(lái)源:億速云 閱讀:182 作者:小新 欄目:編程語(yǔ)言

這篇文章給大家分享的是有關(guān)在Spring中使用數(shù)據(jù)源DBCP、C3P0、JNDI的示例的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。

在 Spring 中,有以下三種方式來(lái)創(chuàng)建數(shù)據(jù)源:

  • 通過(guò) JNDI 獲取應(yīng)用服務(wù)器中的數(shù)據(jù)源;

  • 在 Spring 容器中配置數(shù)據(jù)源;

  • 通過(guò)代碼來(lái)創(chuàng)建數(shù)據(jù)源,這種方式適用于無(wú)容器依賴的單元測(cè)試。

1 配置數(shù)據(jù)源

Spring 在第三方依賴包中包含了 2 種數(shù)據(jù)源的實(shí)現(xiàn)包 一個(gè)是 Apache 的 DBCP;另一個(gè)是 C3P0。 我們可以在 Spring 配置文件中直接配置這些數(shù)據(jù)源 。

1.1 DBCP

DBCP (Database Connection Pool)是一個(gè)依賴 Jakarta commons-pool 對(duì)象池機(jī)制的數(shù)據(jù)庫(kù)連接池,所以在類路徑下還必須包括 commons-pool.jar。 下面是使用 DBCP 配置 MySql 數(shù)據(jù)源的配置片段:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">    
  <property name="driverClassName" value="com.mysql.jdbc.Driver" />    
  <property name="url" value="jdbc:mysql://localhost:3309/db" />    
  <property name="username" value="root" />    
  <property name="password" value="xxxxxx" />    
</bean>

BasicDataSource 提供了 close() 方法用于關(guān)閉數(shù)據(jù)源,所以必須設(shè)定 destroy-method=”close”, 以便 Spring 容器關(guān)閉時(shí),能夠正常關(guān)閉數(shù)據(jù)源。

除以上必須的數(shù)據(jù)源屬性外,還有一些常用的屬性。

事務(wù)屬性:

屬性默認(rèn)值說(shuō)明
defaultAutoCommittrue連接默認(rèn)為 auto-commit 狀態(tài)。
defaultReadOnly驅(qū)動(dòng)默認(rèn)值連接默認(rèn)的 read-only 狀態(tài) 。如果沒(méi)有設(shè)置則 setReadOnly 方法將不會(huì)被調(diào)用。( 某些驅(qū)動(dòng)不支持只讀模式 , 比如:Informix)
defaultTransactionIsolation驅(qū)動(dòng)默認(rèn)值連接默認(rèn)的 TransactionIsolation 狀態(tài)。有這些值:NONE、READ_COMMITTED、READ_UNCOMMITTED、REPEATABLE_READ、SERIALIZABLE。

連接數(shù)相關(guān)屬性:

屬性默認(rèn)值說(shuō)明
initialSize0初始化連接數(shù):連接池啟動(dòng)時(shí)創(chuàng)建的初始化連接數(shù)量。
maxActive8最大活動(dòng)連接 : 連接池在同一時(shí)間內(nèi)能夠分配的最大活動(dòng)連接的數(shù)量。如果設(shè)置為非正數(shù),則表示不限制。
maxIdle8最大空閑連接 : 連接池中容許保持空閑狀態(tài)的最大連接數(shù)量 , 超過(guò)的空閑連接將被釋放 , 如果設(shè)置為負(fù)數(shù),則表示不限制。
minIdle0最小空閑連接 : 連接池中容許保持空閑狀態(tài)的最小連接數(shù)量 , 低于這個(gè)數(shù)量將創(chuàng)建新的連接 , 如果設(shè)置為 0,則表示不創(chuàng)建。
maxWait無(wú)限最大等待時(shí)間 : 當(dāng)沒(méi)有可用連接時(shí) , 連接池等待連接被歸還的最大時(shí)間 ( 單位為毫秒 ) , 超出時(shí)間將拋出異常 , 如果設(shè)置為 -1,則表示無(wú)限等待。

連接監(jiān)測(cè)與維護(hù)相關(guān)屬性:

屬性默認(rèn)值說(shuō)明
validationQuery無(wú)配置 SQL 查詢語(yǔ)句 , 用于驗(yàn)證從連接池取出的連接是否可用。如果指定 , 則查詢必須是一個(gè) SQL SELECT,并且必須返回至少一行記錄。MySQL 中是 “select 1”;在 Oracle 中是 "select 1 from dual"。
testOnBorrowtrue指明是否從連接池中取出連接之前進(jìn)行檢測(cè) , 如果檢測(cè)失敗 , 則從池中去除連接并嘗試取出另一個(gè)新的連接。 注意 : 設(shè)置為 true 后如果要生效,則 validationQuery 參數(shù)必須正確被設(shè)置。
testOnReturnfalse指明是否在歸還到池中前進(jìn)行檢測(cè)。 注意 : 與 testOnBorrow 一樣,設(shè)置為 true 后如果要生效,則 validationQuery 參數(shù)必須正確被設(shè)置。
testWhileIdlefalse指明連接是否會(huì)被空閑連接回收器 ( 如果有 ) 所檢測(cè)。 如果檢測(cè)失敗 , 則連接將從池中被移除。 注意 : 設(shè)置為 true 后如果要生效,則 validationQuery 參數(shù)必須正確被設(shè)置。
timeBetweenEvictionRunsMillis-1空閑連接回收器線程運(yùn)行的周期 , 以毫秒為單位。如果設(shè)置為非正數(shù) , 則不運(yùn)行空閑連接回收器線程。 注意 : 啟用該參數(shù)時(shí),則 validationQuery 參數(shù)必須正確被設(shè)置。
numTestsPerEvictionRun3在每次空閑連接回收器線程 ( 如果有 ) 運(yùn)行時(shí)需要檢測(cè)的連接數(shù)量。
minEvictableIdleTimeMillis1000 * 60 * 30連接在池中保持空閑而不被空閑連接回收器線程回收的最小時(shí)間值,以毫秒為單位。

緩存相關(guān)屬性:

屬性默認(rèn)值說(shuō)明
poolPreparedStatementsfalse開(kāi)啟連接池的 prepared statement 功能設(shè)置為 true 后,所有的 CallableStatement 和 PreparedStatement 都會(huì)被緩存起來(lái)。
maxOpenPreparedStatements不限制能夠同時(shí)分配打開(kāi)的 statements 的最大數(shù)量。0 表示不限制。

連接泄露回收相關(guān)屬性:

屬性默認(rèn)值說(shuō)明
removeAbandonedfalse是否刪除泄露的連接。如果設(shè)置為 true, 那么那些可能存在泄露的連接會(huì)被刪除。假設(shè) maxActive 為 10 個(gè),活動(dòng)連接為 8 個(gè),空閑連接為 1 個(gè),10-8-1=1,那么就會(huì)把刪除這個(gè)連接(會(huì)先檢測(cè)該活動(dòng)連接未被使用的時(shí)間是否超過(guò) removeAbandonedTimeout)。如果需要一個(gè)長(zhǎng)連接操作,那么 removeAbandoned 需要設(shè)置的長(zhǎng)一些,否則正常使用的連接可能會(huì)被誤刪除。
removeAbandonedTimeout300泄露的連接可以被刪除的時(shí)間段,單位為秒。
logAbandonedfalse當(dāng) Statement 或連接被泄露時(shí)是否打印堆棧日志 。

假設(shè)數(shù)據(jù)庫(kù)用的是 MySQL,那么如果數(shù)據(jù)源配置不當(dāng),將可能會(huì)發(fā)生經(jīng)典的 “8 小時(shí)問(wèn)題 ”。 原因是 MySQL 在默認(rèn)情況下如果發(fā)現(xiàn)一個(gè)連接的空閑時(shí)間超過(guò) 8 小時(shí),那么會(huì)在數(shù)據(jù)庫(kù)端自動(dòng)關(guān)閉這個(gè)連接 。 而數(shù)據(jù)源并不知道這個(gè)連接已經(jīng)被關(guān)閉了,所以當(dāng)它將這個(gè)無(wú)用的連接返回給某個(gè) DAO 時(shí), DAO 就會(huì)拋出無(wú)法獲取 connection 的異常 。

DBCP 的 testOnBorrow 默認(rèn)設(shè)置為 true,所以從連接池中取出連接之前會(huì)先進(jìn)行檢測(cè),因?yàn)椴粫?huì)發(fā)生 “8 小時(shí)問(wèn)題 ”。 但如果每次取連接時(shí)都進(jìn)行檢測(cè),那么在高并發(fā)應(yīng)用下就會(huì)產(chǎn)生性能問(wèn)題。

因此建議在高并發(fā)下,將 testOnBorrow 設(shè)置為 false;然后將 testWhileIdle 設(shè)置為 true,打開(kāi)空閑連接回收器;最后把 timeBetweenEvictionRunsMillis 的值設(shè)定為小于 8 小時(shí),這樣那些被 MySQL 所關(guān)閉的空閑連接,就會(huì)被清除出去。這樣不僅解決了 “8 小時(shí)問(wèn)題 ”,而且還保證了高性能 O(∩_∩)O哈哈~

注意:因?yàn)?MySQL 本身的 interactive-timeout(單位為 s)參數(shù),可以設(shè)定空閑連接的過(guò)期時(shí)間,所以我們要想獲取到這個(gè)參數(shù)值,然后再設(shè)定 DBCP 的 timeBetweenEvictionRunsMillis 屬性值。

1.2 C3P0

C3P0 是一個(gè)開(kāi)放源代碼的 JDBC 數(shù)據(jù)源實(shí)現(xiàn)項(xiàng)目,它實(shí)現(xiàn)了 JDBC3 和 JDBC2 擴(kuò)展規(guī)范說(shuō)明的 Connection 和 Statement 池。

下面是使用 C3P0 配置 MySql 數(shù)據(jù)源的配置片段:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">    
  <property name="driverClass" value="oracle.jdbc.driver.OracleDriver" />    
  <property name="jdbcUrl" value="jdbc:mysql://localhost:3309/db" />    
  <property name="use" value="xxx" />    
  <property name="password" value="xxxxxx" />    
</bean>

C3P0 也提供了一個(gè)用于關(guān)閉數(shù)據(jù)源的 close() 方法,這樣我們就可以保證 Spring 容器被關(guān)閉時(shí),能夠成功關(guān)閉數(shù)據(jù)源 。

屬性默認(rèn)值說(shuō)明
acquireIncrement
當(dāng)連接池中無(wú)空閑連接時(shí), 一次性創(chuàng)建新連接的數(shù)量。
acquireRetryAttempts30在從數(shù)據(jù)庫(kù)獲取新連接失敗后,重復(fù)嘗試的次數(shù)。
acquireRetryDelay1000嘗試獲取連接之間的間隔時(shí)間,單位為毫秒。
autoCommitOnClosefalse連接關(guān)閉時(shí),將所有未提交的操作回滾 。
automaticTestTablenull會(huì)創(chuàng)建一張名為 Test 的空表,并使用其自帶的查詢語(yǔ)句進(jìn)行測(cè)試 。 如果定義了這個(gè)參數(shù),那么 preferredTestQuery 屬性 將被忽略 。 我們不能在這張 Test 表上進(jìn)行任何操作,它僅為 C3P0 測(cè)試所用。
breakAfterAcquireFailurefalse獲取連接失敗時(shí),將會(huì)引起所有等待獲取連接的線程拋出異常 。 但是數(shù)據(jù)源仍有效保留,并在下次調(diào)用 getConnection() 時(shí)繼續(xù)嘗試獲取連接 。 在嘗試獲取連接失敗后,該數(shù)據(jù)源將申明已斷開(kāi)并永久關(guān)閉。
checkoutTimeout0當(dāng)連接池中的連接用完時(shí),客戶端調(diào)用 getConnection() 后等待獲取新連接的時(shí)間,單位:毫秒。超時(shí)后將拋出 SQLException 。設(shè)為 0 表示無(wú)限期等待 。
connectionTesterClassNamecom.mchange.v2.C3P0.impl.DefaultConnectionTester通過(guò)實(shí)現(xiàn) ConnectionTester 或 QueryConnectionTester 的類來(lái)測(cè)試連接,類名需設(shè)置為全限定名 。
idleConnectionTestPeriod0隔多少秒,檢查連接池中的所有空閑連接。0 表示不檢查。
initialPoolSize3初始化時(shí)創(chuàng)建的連接數(shù),應(yīng)在 minPoolSize 與 maxPoolSize 之間取值 。
maxIdleTime0最大空閑時(shí)間,超過(guò)空閑時(shí)間的連接將會(huì)被丟棄 。 為 0 或負(fù)數(shù)則表示永不丟棄 。
maxPoolSize15連接池中保留的最大連接數(shù) 。
maxStatements0JDBC 標(biāo)準(zhǔn)參數(shù),用以控制數(shù)據(jù)源內(nèi)加載的 PreparedStatement 數(shù)量 。 但由于預(yù)緩存的 Statement 屬于單個(gè) Connection 而不是整個(gè)連接池 。 所以設(shè)置這個(gè)參數(shù)需要多方面的考慮,如果 maxStatements 與 maxStatementsPerConnection 均為 0 ,則緩存被關(guān)閉 。
maxStatementsPerConnection0連接池內(nèi)單個(gè)連接所擁有的最大緩存 Statement 數(shù) 。
numHelperThreads3C3P0 是異步操作的,緩慢的 JDBC 操作通過(guò) HelperThreads 完成 。 通過(guò)多線程實(shí)現(xiàn)多個(gè)操作同時(shí)被執(zhí)行,這樣可以有效地提升性能。
preferredTestQuerynull定義所有連接測(cè)試都執(zhí)行的測(cè)試語(yǔ)句。在使用連接測(cè)試的情況下,這個(gè)參數(shù)能夠顯著地提高測(cè)試速度。測(cè)試的表必須在初始數(shù)據(jù)源時(shí)就存在。
propertyCycle300修改系統(tǒng)配置參數(shù)生效時(shí)長(zhǎng),單位為 s。
testConnectionOnCheckoutfalse因性能消耗大,所以請(qǐng)只在需要時(shí)開(kāi)啟 。 如果設(shè)為 true 那么在每個(gè) connection 提交的時(shí)候都將校驗(yàn)其有效性 。 建議使用 idleConnectionTestPeriod 或 automaticTestTable 等方法來(lái)提升連接測(cè)試的性能 。
testConnectionOnCheckinfalse如果設(shè)為 true,那么在取得連接的同時(shí)將校驗(yàn)其連接的有效性。

2 JNDI 數(shù)據(jù)源

如果應(yīng)用配置在高性能的應(yīng)用服務(wù)器(如 WebLogic 或 Websphere 等)上,我們可能更希望使用應(yīng)用服務(wù)器所提供的數(shù)據(jù)源 。 應(yīng)用服務(wù)器的數(shù)據(jù)源使用 JNDI 方式來(lái)供調(diào)用者使用, Spring 為此專門(mén)提供了引用 JNDI 資源的 JndiObjectFactoryBean 類 。 下面是一個(gè)簡(jiǎn)單的配置:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"
   p:jndiName="java:comp/env/jdbc/ds"/>

Spring2.0+ 為獲取 J2EE 資源提供了一個(gè) jee 命名空間,通過(guò) jee 命名空間,可以有效地簡(jiǎn)化 J2EE 資源的引用:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
   http://www.springframework.org/schema/jee
   http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
   ">

  <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/ds"/>

</beans>

3 Spring 數(shù)據(jù)源實(shí)現(xiàn)類

Spring 本身也提供了一個(gè)簡(jiǎn)單的數(shù)據(jù)源實(shí)現(xiàn)類 DriverManagerDataSource ,它位于 org.springframework.jdbc.datasource 包中 。 這個(gè)類實(shí)現(xiàn)了 javax.sql.DataSource 接口,但它并沒(méi)有提供池化連接機(jī)制,每次調(diào)用 getConnection() 方法獲取新連接時(shí),只是簡(jiǎn)單地創(chuàng)建一個(gè)新的連接 。它不需要額外的依賴類,所以,這個(gè)數(shù)據(jù)源類比較適合在單元測(cè)試中使用 。

Spring 數(shù)據(jù)源實(shí)現(xiàn)類既可以通過(guò)配置直接使用,也可以在代碼中實(shí)例化調(diào)用:

DriverManagerDataSource dataSource=new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/spring4");
dataSource.setUsername("root");
dataSource.setPassword("");

try {
  Connection connection=dataSource.getConnection();
  if(connection.isClosed()){
    System.out.println("連接已關(guān)閉");
  }else{
    System.out.println("連接已開(kāi)啟");
  }
} catch (SQLException e) {
  e.printStackTrace();
}

感謝各位的閱讀!關(guān)于“在Spring中使用數(shù)據(jù)源DBCP、C3P0、JNDI的示例”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI