細(xì)心!用心!耐心!

          吾非文人,乃市井一俗人也,讀百卷書(shū),跨江河千里,故申城一游; 一兩滴辛酸,三四年學(xué)業(yè),五六點(diǎn)粗墨,七八筆買(mǎi)賣(mài),九十道人情。

          BlogJava 聯(lián)系 聚合 管理
            1 Posts :: 196 Stories :: 10 Comments :: 0 Trackbacks

          簡(jiǎn)單的MySQL連接池

          1. <Resource type="javax.sql.DataSource" 
          2.             name="jdbc/TestDB" 
          3.             factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          4.             driverClassName="com.mysql.jdbc.Driver" 
          5.             url="jdbc:mysql://localhost:3306/mysql" 
          6.             username="mysql_user" 
          7.             password="mypassword123" 
          8. /> 
          第一個(gè)我們需要注意的屬性是factory="org.apache.tomcat.jdbc.pool.DataSourceFactory".

           

          當(dāng)tomcat讀到type="javax.sql.DataSource"屬性時(shí)會(huì)自動(dòng)重新安裝DBCP,除非你指定不同的factory。factory object 本身就是創(chuàng)建和配置連接池的。

          在Apache Tomcat中有兩種方式配置 Resource elements

          配置全局連接池

          編輯conf/server.xml

          1. <GlobalNamingResources> 
          2.   <Resource type="javax.sql.DataSource" 
          3.             name="jdbc/TestDB" 
          4.             factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          5.             driverClassName="com.mysql.jdbc.Driver" 
          6.             url="jdbc:mysql://localhost:3306/mysql" 
          7.             username="mysql_user" 
          8.             password="mypassword123" 
          9. /> 
          10. </GlobalNamingResources> 

          然后你需要?jiǎng)?chuàng)建一個(gè)ResourceLink element使這個(gè)連接池對(duì)于web應(yīng)用是可用的。如果你想要用同一個(gè)名字讓連接池對(duì)于所有的應(yīng)用有效,最簡(jiǎn)單的方法就是編輯conf/context.xml文件

           

          1. <Context> 
          2.   <ResourceLink type="javax.sql.DataSource" 
          3.                 name="jdbc/LocalTestDB" 
          4.                 global="jdbc/TestDB" 
          5. /> 
          6. <Context> 

          注意,如果你不想要全局的連接池,可以從server.xml移除Resource element到你的web應(yīng)用的context.xml 文件。

           

          然后從剛配置好的連接池中獲得連接,簡(jiǎn)單java代碼:

          1. Context initContext = new InitialContext(); 
          2. Context envContext  = (Context)initContext.lookup("java:/comp/env"); 
          3. DataSource datasource = (DataSource)envContext.lookup("jdbc/LocalTestDB"); 
          4. Connection con = datasource.getConnection(); 

           

          使用java很簡(jiǎn)單

          還可以使用Java syntax

          1. DataSource ds = new DataSource(); 
          2. ds.setDriverClassName("com.mysql.jdbc.Driver"); 
          3. ds.setUrl("jdbc:mysql://localhost:3306/mysql"); 
          4. ds.setUsername("root"); 
          5. ds.setPassword("password"); 
          或者分離出連接池的屬性

           

          1. PoolProperties pp = new PoolProperties(); 
          2. pp.setDriverClassName("com.mysql.jdbc.Driver"); 
          3. pp.setUrl("jdbc:mysql://localhost:3306/mysql"); 
          4. pp.setUsername("root"); 
          5. pp.setPassword("password"); 
          6. DataSource ds = new DataSource(pp); 
          所有的屬性我們可以在XML中通過(guò)factory object也可以直接使用PoolProperties或者DataSource objects設(shè)置為有效

           

          設(shè)置連接池

          我們將使用下面這些屬性設(shè)置連接池

          •    initialSize
          •     maxActive
          •     maxIdle
          •     minIdle

          去了解這些屬性是很重要的,它們看起來(lái)很明顯但又有一些神秘

          1. <Resource type="javax.sql.DataSource" 
          2.             name="jdbc/TestDB" 
          3.             factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          4.             driverClassName="com.mysql.jdbc.Driver" 
          5.             url="jdbc:mysql://localhost:3306/mysql" 
          6.             username="mysql_user" 
          7.             password="mypassword123" 
          8.             initialSize="10" 
          9.             maxActive="100" 
          10.             maxIdle="50" 
          11.             minIdle="10" 
          12.             /> 

          initialSize=10 設(shè)置連接池建立時(shí)連接的數(shù)目

           

          • 當(dāng)連接池定義在GlobalNamingResources中,連接池在Tomcat啟動(dòng)時(shí)創(chuàng)鍵
          • 當(dāng)連接池定義在Context中,連接池在第一次查找JNDI時(shí)創(chuàng)建

          maxActive=100 連接數(shù)據(jù)庫(kù)的最大連接數(shù)。這個(gè)屬性用來(lái)限制連接池中能夠打開(kāi)連接的數(shù)量,可以方便數(shù)據(jù)庫(kù)做連接容量規(guī)劃。

          minIdle=10  連接池中存在的最小連接數(shù)目。連接池中連接數(shù)目可以變很少,如果使用了maxAge屬性,有些空閑的連接會(huì)被關(guān)閉因?yàn)殡x它最近一次連接的時(shí)間過(guò)去太久了。但是,我們看到的打開(kāi)的連接不會(huì)少于minIdle

          maxIdle屬性有一點(diǎn)麻煩。它的不同的行為取決于是否使用了pool sweeperpool sweeper是一個(gè)可以在連接池正在使用的時(shí)候測(cè)試空閑連接和重置連接池大小的后臺(tái)線程。還負(fù)責(zé)檢測(cè)連接泄露。pool sweeper 通過(guò)如下方式定義的:

          1. public boolean isPoolSweeperEnabled() { 
          2.         boolean timer = getTimeBetweenEvictionRunsMillis()>0; 
          3.         boolean result = timer && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0); 
          4.         result = result || (timer && getSuspectTimeout()>0);  
          5.         result = result || (timer && isTestWhileIdle() && getValidationQuery()!=null); 
          6.         return result; 
          7.     } 

          sweepertimeBetweenEvictionRunsMillis milliseconds運(yùn)行一次。

           

          maxIdle定義如下

          • Pool sweeper關(guān)閉,如果空閑連接池大于maxIdle,返回的連接將被關(guān)閉。
          • Pool sweeper開(kāi)啟,空閑的連接數(shù)可以超過(guò)maxIdle,但如果連接空閑的時(shí)間已經(jīng)超過(guò)minEvictableIdleTimeMillis,能縮小到minIdle。聽(tīng)起來(lái)很奇怪連接池為什么不關(guān)閉連接當(dāng)空閑連接數(shù)量大于maxIdle。想想下面的情況:  
          1. 100個(gè)線程處理100個(gè)并發(fā)請(qǐng)求   
          2. 在一個(gè)請(qǐng)求中每個(gè)線程請(qǐng)求一個(gè)連接3次 

          在這種場(chǎng)景下,如果我們?cè)O(shè)置maxIdle=50,那么我們會(huì)關(guān)閉和打開(kāi)50*3的連接數(shù)。這樣增加了數(shù)據(jù)庫(kù)的負(fù)重并且減慢了應(yīng)用的速度。當(dāng)達(dá)到連接高峰時(shí),我們希望能夠充分利用連接池中的所有連接。因此,我們強(qiáng)烈希望打開(kāi)pool sweeper 。我們將在下一個(gè)部分探討具體的事項(xiàng)。我們?cè)谶@里額外說(shuō)明maxAge這個(gè)屬性。maxAge定義連接能夠打開(kāi)或者存在的時(shí)間,單位為毫秒。當(dāng)一個(gè)連接返回到了連接池,如果這個(gè)連接已經(jīng)使用過(guò),并且距離它第一次被使用的時(shí)間大于maxAge時(shí),這個(gè)連接會(huì)被關(guān)閉。

          正如我們所看到的 isPoolSweeper算法實(shí)現(xiàn),sweeper 將會(huì)被打開(kāi),當(dāng)以下任一條件滿足時(shí)

          • timeBetweenEvictionRunsMillis>0 AND removeAbandoned=true ANDremoveAbandonedTimeout>0
          • timeBetweenEvictionRunsMillis>0 AND suspectTimeout>0
          • timeBetweenEvictionRunsMillis>0 AND testWhileIdle=true AND validationQuery!=null

                        As of version 1.0.9 the following condition has been added

          • timeBetweenEvictionRunsMillis>0 AND minEvictableIdleTimeMillis>0

                       (timer && getMinEvictableIdleTimeMillis()>0);

          因此設(shè)置最理想的連接池,我們最好修改我們的配置滿足這些條件

          1. <Resource type="javax.sql.DataSource" 
          2.             name="jdbc/TestDB" 
          3.             factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          4.             driverClassName="com.mysql.jdbc.Driver" 
          5.             url="jdbc:mysql://localhost:3306/mysql" 
          6.             username="mysql_user" 
          7.             password="mypassword123" 
          8.             initialSize="10" 
          9.             maxActive="100" 
          10.             maxIdle="50" 
          11.             minIdle="10" 
          12.             suspectTimeout="60" 
          13.             timeBetweenEvictionRunsMillis="30000" 
          14.             minEvictableIdleTimeMillis="60000" 
          15.             /> 

           

          有效的連接

          數(shù)據(jù)庫(kù)連接池提出了一個(gè)挑戰(zhàn),因?yàn)檫B接池中的連接會(huì)過(guò)時(shí)。這是常有的事,要么數(shù)據(jù)庫(kù),或者可能是連接池和數(shù)據(jù)庫(kù)中的一個(gè)設(shè)備,連接超時(shí)。唯一確定會(huì)話連接是活躍的真正辦法是使連接在服務(wù)器和數(shù)據(jù)庫(kù)做一個(gè)來(lái)回訪問(wèn)。在Java 6中,JDBC API處理驗(yàn)證連接是否是有效的方法是通過(guò)提供isValid變量來(lái)調(diào)用java.sql.Connection接口。在此之前,連接池不得不采用執(zhí)行一個(gè)查詢(xún)的方法,比如在MySQL上執(zhí)行SELECT 1.數(shù)據(jù)庫(kù)分析這句查詢(xún)很簡(jiǎn)單,不需要任何的磁盤(pán)訪問(wèn)。isValid被計(jì)劃實(shí)施,但 Apache Tomcat 6的連接池,也必須保存對(duì)Java 5的兼容性。

          校驗(yàn)查詢(xún)

          校驗(yàn)查詢(xún)會(huì)有一些挑戰(zhàn)

          1. 如果它們頻繁使用,會(huì)降低系統(tǒng)的性能
          2. 如果使用的間隔太久,會(huì)導(dǎo)致連接失效
          3. 如果應(yīng)用調(diào)用setTransactionIsolation并設(shè)置autoCommit=false,如果應(yīng)用再次調(diào)用setTransactionIsolation,會(huì)產(chǎn)生一個(gè)SQLException異常,因?yàn)樾r?yàn)查詢(xún)可能在數(shù)據(jù)庫(kù)中已經(jīng)產(chǎn)生了一個(gè)新的transaction。

          讓我們看看最典型的配置:

          1. <Resource type="javax.sql.DataSource" 
          2.            name="jdbc/TestDB" 
          3.            factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          4.            driverClassName="com.mysql.jdbc.Driver" 
          5.            url="jdbc:mysql://localhost:3306/mysql" 
          6.            username="mysql_user" 
          7.            password="mypassword123" 
          8.            testOnBorrow="true" 
          9.            validationQuery="SELECT 1" 
          10.            /> 

          在這個(gè)配置中,java代碼每次調(diào)用 Connection con = dataSource.getConnection()時(shí)都會(huì)執(zhí)行一次SELECT 1查詢(xún)。

           

          這樣保證了在連接提交給應(yīng)用之前都已經(jīng)測(cè)試過(guò)了。但是,對(duì)于在短時(shí)間內(nèi)頻繁使用連接的應(yīng)用,會(huì)對(duì)性能有嚴(yán)重的影響。這有兩個(gè)其他的配置選項(xiàng):

          • testWhileIdle
          • testOnReturn

          當(dāng)在錯(cuò)誤的時(shí)間對(duì)連接做測(cè)試,它們也不是真正的很有幫助。

          對(duì)于很多應(yīng)用來(lái)說(shuō),沒(méi)有校驗(yàn)不是一個(gè)真正的困難。一些應(yīng)用可以繞過(guò)校驗(yàn)通過(guò)設(shè)置minIdle=0和給minEvictableIdleTimeMillis一個(gè)很小的值,所以如果連接空閑了足夠長(zhǎng)的時(shí)間會(huì)讓數(shù)據(jù)庫(kù)會(huì)話超時(shí),在此之前連接池將會(huì)移除這些空閑太久的連接。

          最好的解決辦法就是測(cè)試那些有一段時(shí)間沒(méi)被測(cè)試過(guò)的連接。

          1. <Resource type="javax.sql.DataSource" 
          2.             name="jdbc/TestDB" 
          3.             factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          4.             driverClassName="com.mysql.jdbc.Driver" 
          5.             url="jdbc:mysql://localhost:3306/mysql" 
          6.             username="mysql_user" 
          7.             password="mypassword123" 
          8.             testOnBorrow="true" 
          9.             validationQuery="SELECT 1" 
          10.             validationInterval="30000" 
          11.             /> 

          在這個(gè)配置中,連接校驗(yàn)的間隔不會(huì)超過(guò)30s。這是在性能和連接驗(yàn)證上的折中。正如前面提到的,如果我們想僥幸驗(yàn)證所有的連接,我們可以配置連接池中所有空閑連接超時(shí)。

           

          1. <Resource type="javax.sql.DataSource" 
          2.             name="jdbc/TestDB" 
          3.             factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          4.             driverClassName="com.mysql.jdbc.Driver" 
          5.             url="jdbc:mysql://localhost:3306/mysql" 
          6.             username="mysql_user" 
          7.             password="mypassword123" 
          8.             timeBetweenEvictionRunsMillis="5000" 
          9.             minEvictableIdleTimeMillis="5000" 
          10.             minIdle="0" 
          11.             /> 

           

          建立數(shù)據(jù)庫(kù)客戶會(huì)話

          在一些案例中,當(dāng)初始化一個(gè)新的數(shù)據(jù)庫(kù)會(huì)話時(shí)需要執(zhí)行一些任務(wù)。可能包括執(zhí)行一個(gè)簡(jiǎn)單的SQL聲明或者執(zhí)行一個(gè)存儲(chǔ)過(guò)程。
          當(dāng)你創(chuàng)建觸發(fā)器時(shí)候,這是在數(shù)據(jù)庫(kù)層面上的典型操作。

          1. create or replace trigger logon_alter_session after logon on database 
          2.   begin 
          3.     if sys_context('USERENV', 'SESSION_USER') = 'TEMP' then 
          4.       EXECUTE IMMEDIATE 'alter session ....'; 
          5.     end if; 
          6.   end; 
          7.   / 

          這將影響所有的用戶,在后面這種情況下這是不夠的,當(dāng)創(chuàng)建一個(gè)新的會(huì)話的時(shí)候我們希望執(zhí)行一個(gè)自定義查詢(xún)。

           

          1. <Resource name="jdbc/TestDB" auth="Container" 
          2.             type="javax.sql.DataSource" 
          3.             description="Oracle Datasource" 
          4.             url="jdbc:oracle:thin:@//localhost:1521/orcl" 
          5.             driverClassName="oracle.jdbc.driver.OracleDriver" 
          6.             username="default_user" 
          7.             password="password" 
          8.             maxActive="100" 
          9.             validationQuery="select 1 from dual" 
          10.             validationInterval="30000" 
          11.             testOnBorrow="true" 
          12.             initSQL="ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY MM DD HH24:MI:SS'"/> 

          initSQL會(huì)被存在的每一條連接執(zhí)行。

           

          連接池泄露和長(zhǎng)時(shí)間運(yùn)行的查詢(xún)

          連接池包含一些診斷操作。jdbc-pool和Common DBCP都能夠檢測(cè)和減輕沒(méi)有返回連接池中的連接。這里演示是被稱(chēng)為拋出內(nèi)存泄露的連接。

          1. Connection con = dataSource.getConnection(); 
          2. Statement st = con.createStatement(); 
          3. st.executeUpdate("insert into id(value) values (1'); //SQLException here 
          4. con.close(); 
          這有5個(gè)配置選項(xiàng)用來(lái)檢測(cè)這些錯(cuò)誤類(lèi)型的連接,前三個(gè)選項(xiàng)配置在Common DBCP中也有

           

          1. <Resource type="javax.sql.DataSource" 
          2.             name="jdbc/TestDB" 
          3.             factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          4.             driverClassName="com.mysql.jdbc.Driver" 
          5.             url="jdbc:mysql://localhost:3306/mysql" 
          6.             username="mysql_user" 
          7.             password="mypassword123" 
          8.             maxActive="100" 
          9.             timeBetweenEvictionRunsMillis="30000" 
          10.             removeAbandoned="true" 
          11.             removeAbandonedTimeout="60" 
          12.             logAbandoned="true" 
          13.             /> 

           

          • removeAbandoned-如果我們想檢測(cè)內(nèi)存泄露的連接,可以設(shè)置為true
          • removeAbandonedTimeout-調(diào)用dataSource.getConnection開(kāi)始到丟棄檢測(cè)到泄露連接的時(shí)間(seconds)
          • logAbandoned-如果想用log記錄丟棄的連接,可以設(shè)置為true。當(dāng)設(shè)置為true時(shí),調(diào)用dataSource.getConnection 時(shí)會(huì)記錄一個(gè)堆棧追蹤,并且被打印出來(lái)當(dāng)連接沒(méi)有返回的時(shí)候。

          但我們想要這種類(lèi)型的診斷,當(dāng)然有可以使用的例子。也可以運(yùn)行批處理作業(yè)一次執(zhí)行一個(gè)連接幾分鐘。我們?cè)撊绾翁幚磉@些問(wèn)題?
          兩個(gè)額外的選項(xiàng)已經(jīng)被加入來(lái)支持這些工作

          1. <Resource type="javax.sql.DataSource" 
          2.            name="jdbc/TestDB" 
          3.            factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          4.            driverClassName="com.mysql.jdbc.Driver" 
          5.            url="jdbc:mysql://localhost:3306/mysql" 
          6.            username="mysql_user" 
          7.            password="mypassword123" 
          8.            maxActive="100" 
          9.            timeBetweenEvictionRunsMillis="30000" 
          10.            removeAbandoned="true" 
          11.            removeAbandonedTimeout="60" 
          12.            logAbandoned="true" 
          13.            abandonWhenPercentageFull="50" 
          14.            /> 

           

          • abandonWhenPercentageFull-一條連接必須滿足臨界值 removeAbandonedTimeout和打開(kāi)連接的數(shù)量必須超過(guò)這個(gè)百分比。


          使用這個(gè)屬性可能會(huì)在一次錯(cuò)誤判斷中產(chǎn)生在其他地方已經(jīng)被認(rèn)為丟棄的連接。設(shè)置這個(gè)值為100時(shí)意味著連接數(shù)除非到了maxActive限制時(shí),是不會(huì)被考慮丟棄的。這給連接池增加了一些靈活性,但是不會(huì)讓批處理作業(yè)使用單獨(dú)連接5分鐘。在這種情況,我們想確定當(dāng)我們檢測(cè)到連接仍然被使用時(shí),我們重置超時(shí)計(jì)時(shí)器,因此,連接不會(huì)被考慮丟棄。我們通過(guò)插入一個(gè)攔截器實(shí)現(xiàn)。

          1. <Resource type="javax.sql.DataSource" 
          2.             name="jdbc/TestDB" 
          3.             factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          4.             driverClassName="com.mysql.jdbc.Driver" 
          5.             url="jdbc:mysql://localhost:3306/mysql" 
          6.             username="mysql_user" 
          7.             password="mypassword123" 
          8.             maxActive="100" 
          9.             timeBetweenEvictionRunsMillis="30000" 
          10.             removeAbandoned="true" 
          11.             removeAbandonedTimeout="60" 
          12.             logAbandoned="true" 
          13.             abandonWhenPercentageFull="50" 
          14.             jdbcInterceptors="ResetAbandonedTimer" 
          15.             />  

          攔截器在org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer中被指定完全限定名稱(chēng),或者在org.apache.tomcat.jdbc.pool.interceptor包中使用短類(lèi)名
          每次準(zhǔn)備語(yǔ)句或者執(zhí)行一次查詢(xún),連接池中的計(jì)時(shí)器會(huì)被重置放棄計(jì)時(shí)器。因?yàn)槿绱耍?分鐘的批處理作業(yè)中執(zhí)行多次查詢(xún)和更新,都不會(huì)超時(shí)。

           

          這是你當(dāng)然想知道的情形,但你不會(huì)想去kill或者回收連接,因?yàn)槟悴粫?huì)知道會(huì)對(duì)你的系統(tǒng)產(chǎn)生什么影響。

          1. <Resource type="javax.sql.DataSource" 
          2.             name="jdbc/TestDB" 
          3.             factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          4.             driverClassName="com.mysql.jdbc.Driver" 
          5.             url="jdbc:mysql://localhost:3306/mysql" 
          6.             username="mysql_user" 
          7.             password="mypassword123" 
          8.             maxActive="100" 
          9.             timeBetweenEvictionRunsMillis="30000" 
          10.             logAbandoned="true" 
          11.             suspectTimeout="60" 
          12.             jdbcInterceptors="ResetAbandonedTimer" 
          13.             /> 

          suspectTimeout屬性的工作方式與removeAbandonedTimeout 相似,除了不關(guān)閉連接,而只是簡(jiǎn)單的記錄警告和發(fā)布一個(gè)JMX通知信息。通過(guò)這種方式,你可以在不用改變你系統(tǒng)行為的情況下發(fā)現(xiàn)泄漏或者長(zhǎng)查詢(xún)。

           

          從其它的數(shù)據(jù)源形成連接池

          到目前為止我們處理連接池連接的獲得是通過(guò)java.sql.Driver接口。因此我們使用屬性

          • driverClassName
          • url

          然而,一些連接配置是使用 javax.sql.DataSource 甚至是javax.sql.XADataSource接口,因此我們需要支持這些配置選項(xiàng)。
          使用java相對(duì)是很容易的。

          1.     PoolProperties pp = new PoolProperties(); 
          2. pp.setDataSource(myOtherDataSource); 
          3. DataSource ds = new DataSource(pp); 
          4. Connection con = ds.getConnection(); 
          或者

           

          1.     DataSource ds = new DataSource(); 
          2. ds.setDataSource(myOtherDataSource); 
          3. Connection con = ds.getConnection(); 
          我們能夠注入另外的 javax.sql.DataSource或者 javax.sql.XADataSource對(duì)象并且用來(lái)連接檢索。
          在我們處理XA連接時(shí)很方便。

           

          在XML配置中,jdbc-pool會(huì)使用org.apache.tomcat.jdbc.naming.GenericNamingResourcesFactory類(lèi),一個(gè)能夠允許配置任何類(lèi)型的命名資源的簡(jiǎn)單類(lèi)。為了設(shè)置Apache Derby XADataSource 我們可以創(chuàng)建了下面的代碼

          1. <Resource factory="org.apache.tomcat.jdbc.naming.GenericNamingResourcesFactory"  
          2.             name="jdbc/DerbyXA1" 
          3.             type="org.apache.derby.jdbc.ClientXADataSource" 
          4.             databaseName="sample1" 
          5.             createDatabase="create" 
          6.             serverName="localhost" 
          7.             portNumber="1527" 
          8.             user="sample1" 
          9.             password="password"/> 

          這是一個(gè)簡(jiǎn)單的通過(guò)端口1527連接到網(wǎng)絡(luò)上的相鄰實(shí)例的XADataSource.

           

          如果你想要從這個(gè)數(shù)據(jù)源形成XA連接池,我們可以在它后面建立這個(gè)連接池節(jié)點(diǎn)。

          1. <Resource factory="org.apache.tomcat.jdbc.naming.GenericNamingResourcesFactory" 
          2.             name="jdbc/DerbyXA1" 
          3.             type="org.apache.derby.jdbc.ClientXADataSource" 
          4.             databaseName="sample1" 
          5.             createDatabase="create" 
          6.             serverName="localhost" 
          7.             portNumber="1527" 
          8.             user="sample1" 
          9.             password="password"/> 
          10.             <Resource factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          11.             dataSourceJNDI="DerbyXA1"<!--Links to the Derby XADataSource--> 
          12.             name="jdbc/TestDB1" 
          13.             auth="Container" 
          14.             type="javax.sql.XADataSource" 
          15.             testWhileIdle="true" 
          16.             testOnBorrow="true" 
          17.             testOnReturn="false" 
          18.             validationQuery="SELECT 1" 
          19.             validationInterval="30000" 
          20.             timeBetweenEvictionRunsMillis="5000" 
          21.             maxActive="100" 
          22.             minIdle="10" 
          23.             maxIdle="20" 
          24.             maxWait="10000" 
          25.             initialSize="10" 
          26.             removeAbandonedTimeout="60" 
          27.             removeAbandoned="true" 
          28.             logAbandoned="true" 
          29.             minEvictableIdleTimeMillis="30000" 
          30.             jmxEnabled="true" 
          31.             jdbcInterceptors="ConnectionState;StatementFinalizer;SlowQueryReportJmx(threshold=10000)" 
          32.             abandonWhenPercentageFull="75"/> 
          注意 type=javax.sql.XADataSource 是怎樣設(shè)置的,這會(huì)創(chuàng)建一個(gè)org.apache.tomcat.jdbc.pool.XADataSource來(lái)代替org.apache.tomcat.jdbc.pool.DataSource
          這里我們通過(guò)dataSourceJNDI=DerbyXA1屬性鏈接這兩個(gè)數(shù)據(jù)源。這兩個(gè)數(shù)據(jù)源都不得不存在同一個(gè)命名空間,在我們的例子中,是jdbc命名空間。

           

          目前JNDI通過(guò)DataSource.setDataSourceJNDI(...)查找不被支持,只能通過(guò)factory對(duì)象。

          如果你加入一個(gè)

          • javax.sql.DataSource對(duì)象-連接池將會(huì)調(diào)用 javax.sql.DataSource.getConnection()方法
          • javax.sql.DataSource 對(duì)象但是在連接池中指定了username/password-連接池將會(huì)調(diào)用javax.sql.DataSource.getConnection(String username, String password) 方法
          • javax.sql.XADataSource對(duì)象-連接池將會(huì)調(diào)用 javax.sql.XADataSource.getXAConnection()方法
          • javax.sql.XADataSource 對(duì)象但是在連接池中指定了 username/password-連接池將會(huì)調(diào)用 javax.sql.DataSource.getXAConnection(String username, String password)方法

          這是一個(gè)有趣的現(xiàn)象當(dāng)你處理 XADataSources。你可以把返回的對(duì)象轉(zhuǎn)換為java.sql.Connection對(duì)象或者javax.sql.XAConnection對(duì)象,并且對(duì)同一個(gè)對(duì)象的兩個(gè)接口調(diào)用方法。

          1.     DataSource ds = new DataSource(); 
          2. ds.setDataSource(myOtherDataSource); 
          3. Connection con = ds.getConnection(); 
          4. if (con instanceof XAConnection) { 
          5.         XAConnection xacon = (XAConnection)con; 
          6.         transactionManager.enlistResource(xacon.getXAResource()); 
          7. Statement st = con.createStatement(); 
          8. ResultSet rs = st.executeQuery(SELECT 1); 

           

          JDBC 攔截器

          JDBC 攔截器創(chuàng)建是為了實(shí)現(xiàn)靈活性。javax.sql.PooledConnection 從底層驅(qū)動(dòng)封裝了java.sql.Connection/javax.sql.XAConnection或者數(shù)據(jù)源本身就是一個(gè)攔截器。攔截器以java.lang.reflect.InvocationHandler接口為基礎(chǔ)。攔截器是一個(gè)繼承自org.apache.tomcat.pool.jdbc.JdbcInterceptor的類(lèi)。

          在本文中,我們將介紹如果配置攔截器。在我們下一篇文章,我們將介紹如果實(shí)現(xiàn)自定義攔截器和它們的生命周期。

          1. <Resource factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          2.   
          3.             ... 
          4.             jdbcInterceptors="ConnectionState;StatementFinalizer;SlowQueryReportJmx(threshold=10000)" 
          5.   
          6.   /> 

          與下面的相同

           

          1. <Resource factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          2.   
          3.             ... 
          4.            jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState; 
          5.            org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer; 
          6.            org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx(threshold=10000)" 
          7.   /> 

          攔截器可以使用一個(gè)短小的名稱(chēng),比如ConnectionState,如果這個(gè)攔截器定義在org.apache.tomcat.jdbc.pool.interceptor 包中。

           

          否則,必須使用一個(gè)完全限定名稱(chēng)。

          攔截器定義在以;分割的字符串中。攔截器可以在括號(hào)內(nèi)定義0個(gè)或多個(gè)參數(shù)。參數(shù)是以逗號(hào)分割的簡(jiǎn)單鍵值對(duì)。

          連接狀態(tài)

          java.sql.Connection接口有如下屬性

          •        autoCommit
          •         readOnly
          •         transactionIsolation
          •         catalog

          這些屬性的默認(rèn)值可以使用如下的內(nèi)容為連接池配置

          •         defaultAutoCommit
          •         defaultReadOnly
          •         defaultTransactionIsolation
          •         defaultCatalog

          如果設(shè)置了這些屬性,當(dāng)建立連接到數(shù)據(jù)庫(kù)時(shí)配置這個(gè)連接。如果沒(méi)有配置 ConnectionState攔截器,在建立連接時(shí)設(shè)置這些屬性會(huì)是一次性操作。如果配置了ConnectionState攔截器,每次從連接池取出的連接會(huì)將被重置為期望的狀態(tài)。

          其中有些方法在執(zhí)行查詢(xún)時(shí)會(huì)導(dǎo)致往返數(shù)據(jù)庫(kù)。比如,調(diào)用 Connection.getTransactionIsolation()會(huì)導(dǎo)致驅(qū)動(dòng)查詢(xún)當(dāng)前會(huì)話的事務(wù)隔離級(jí)別。這種往返會(huì)導(dǎo)致嚴(yán)重的性能問(wèn)題并影響應(yīng)用在頻繁的使用連接執(zhí)行非常短和快的操作的時(shí)候。 ConnectionState 攔截器可以緩存這些操作的值并調(diào)用方法查詢(xún)它們從而避免往返數(shù)據(jù)庫(kù)。

          Statement Finalizer

          java代碼在使用java.sql對(duì)象后需要清除和釋放使用過(guò)的資源。

          一個(gè)清理代碼示例

          1.            Connection con = null
          2. Statement st = null
          3. ResultSet rs = null
          4. try { 
          5.             con = ds.getConnection(); 
          6.             ... 
          7.  
          8. } finally { 
          9.             if (rs!=null) try  { rs.close(); } catch (Exception ignore){} 
          10.             if (st!=null) try  { st.close(); } catch (Exception ignore){} 
          11.             if (con!=null) try { con.close();} catch (Exception ignore){} 
          一些應(yīng)用并不總是使用這種方式。我們以前展示了如何配置連接池去診斷和警告當(dāng)連接沒(méi)有正確關(guān)閉的情況。

           

          當(dāng)一個(gè)連接返回連接池的時(shí)候,StatementFinalizer攔截器確保 java.sql.Statement和它的子類(lèi)正確關(guān)閉。

          獲得真正的JDBC連接

          使用javax.sql.PooledConnection工具返回代理連接,因此取出連接十分直接,不需要轉(zhuǎn)換為特殊的類(lèi)。

          同樣適用于你配置了處理javax.sql.XAConnection的連接池。

          另一個(gè)有趣的取出底層連接的方法是

          1. Connection con = ds.getConnection(); 
          2. ction underlyingconnection = con.createStatement().getConnection(); 
          這是因?yàn)閖dbc-pool默認(rèn)的是沒(méi)有代理聲明。這當(dāng)然有一個(gè)攔截器用來(lái)阻止這個(gè)用例。
          posted on 2014-07-29 10:03 張金鵬 閱讀(644) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 静安区| 宁阳县| 禹城市| 柳江县| 铁岭市| 南丰县| 客服| 定西市| 门头沟区| 香格里拉县| 嘉义县| 郴州市| 广饶县| 潞城市| 正阳县| 泊头市| 石泉县| 冀州市| 洪湖市| 阳江市| 手游| 沧州市| 唐河县| 宣威市| 东乡族自治县| 额尔古纳市| 河津市| 黑山县| 旌德县| 平乐县| 九龙县| 明溪县| 定南县| 南乐县| 资中县| 方山县| 渭源县| 横峰县| 明水县| 阿瓦提县| 会理县|