<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

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

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

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

    簡單的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í)會自動重新安裝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> 

    然后你需要創(chuàng)建一個(gè)ResourceLink element使這個(gè)連接池對于web應(yīng)用是可用的。如果你想要用同一個(gè)名字讓連接池對于所有的應(yīng)用有效,最簡單的方法就是編輯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 文件。

     

    然后從剛配置好的連接池中獲得連接,簡單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很簡單

    還可以使用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中通過factory object也可以直接使用PoolProperties或者DataSource objects設(shè)置為有效

     

    設(shè)置連接池

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

    •    initialSize
    •     maxActive
    •     maxIdle
    •     minIdle

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

    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啟動時(shí)創(chuàng)鍵
    • 當(dāng)連接池定義在Context中,連接池在第一次查找JNDI時(shí)創(chuàng)建

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

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

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

    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開啟,空閑的連接數(shù)可以超過maxIdle,但如果連接空閑的時(shí)間已經(jīng)超過minEvictableIdleTimeMillis,能縮小到minIdle。聽起來很奇怪連接池為什么不關(guān)閉連接當(dāng)空閑連接數(shù)量大于maxIdle。想想下面的情況:  
    1. 100個(gè)線程處理100個(gè)并發(fā)請求   
    2. 在一個(gè)請求中每個(gè)線程請求一個(gè)連接3次 

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

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

    校驗(yàn)查詢

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

    1. 如果它們頻繁使用,會降低系統(tǒng)的性能
    2. 如果使用的間隔太久,會導(dǎo)致連接失效
    3. 如果應(yīng)用調(diào)用setTransactionIsolation并設(shè)置autoCommit=false,如果應(yīng)用再次調(diào)用setTransactionIsolation,會產(chǎn)生一個(gè)SQLException異常,因?yàn)樾r?yàn)查詢可能在數(shù)據(jù)庫中已經(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í)都會執(zhí)行一次SELECT 1查詢。

     

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

    • testWhileIdle
    • testOnReturn

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

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

    最好的解決辦法就是測試那些有一段時(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.             testOnBorrow="true" 
    9.             validationQuery="SELECT 1" 
    10.             validationInterval="30000" 
    11.             /> 

    在這個(gè)配置中,連接校驗(yàn)的間隔不會超過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ù)庫客戶會話

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

    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è)新的會話的時(shí)候我們希望執(zhí)行一個(gè)自定義查詢。

     

    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會被存在的每一條連接執(zhí)行。

     

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

    連接池包含一些診斷操作。jdbc-pool和Common DBCP都能夠檢測和減輕沒有返回連接池中的連接。這里演示是被稱為拋出內(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)用來檢測這些錯(cuò)誤類型的連接,前三個(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-如果我們想檢測內(nèi)存泄露的連接,可以設(shè)置為true
    • removeAbandonedTimeout-調(diào)用dataSource.getConnection開始到丟棄檢測到泄露連接的時(shí)間(seconds)
    • logAbandoned-如果想用log記錄丟棄的連接,可以設(shè)置為true。當(dāng)設(shè)置為true時(shí),調(diào)用dataSource.getConnection 時(shí)會記錄一個(gè)堆棧追蹤,并且被打印出來當(dāng)連接沒有返回的時(shí)候。

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

    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和打開連接的數(shù)量必須超過這個(gè)百分比。


    使用這個(gè)屬性可能會在一次錯(cuò)誤判斷中產(chǎn)生在其他地方已經(jīng)被認(rèn)為丟棄的連接。設(shè)置這個(gè)值為100時(shí)意味著連接數(shù)除非到了maxActive限制時(shí),是不會被考慮丟棄的。這給連接池增加了一些靈活性,但是不會讓批處理作業(yè)使用單獨(dú)連接5分鐘。在這種情況,我們想確定當(dāng)我們檢測到連接仍然被使用時(shí),我們重置超時(shí)計(jì)時(shí)器,因此,連接不會被考慮丟棄。我們通過插入一個(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中被指定完全限定名稱,或者在org.apache.tomcat.jdbc.pool.interceptor包中使用短類名
    每次準(zhǔn)備語句或者執(zhí)行一次查詢,連接池中的計(jì)時(shí)器會被重置放棄計(jì)時(shí)器。因?yàn)槿绱耍?分鐘的批處理作業(yè)中執(zhí)行多次查詢和更新,都不會超時(shí)。

     

    這是你當(dāng)然想知道的情形,但你不會想去kill或者回收連接,因?yàn)槟悴粫罆δ愕南到y(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)閉連接,而只是簡單的記錄警告和發(fā)布一個(gè)JMX通知信息。通過這種方式,你可以在不用改變你系統(tǒng)行為的情況下發(fā)現(xiàn)泄漏或者長查詢。

     

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

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

    • driverClassName
    • url

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

    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對象并且用來連接檢索。
    在我們處理XA連接時(shí)很方便。

     

    在XML配置中,jdbc-pool會使用org.apache.tomcat.jdbc.naming.GenericNamingResourcesFactory類,一個(gè)能夠允許配置任何類型的命名資源的簡單類。為了設(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è)簡單的通過端口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è)置的,這會創(chuàng)建一個(gè)org.apache.tomcat.jdbc.pool.XADataSource來代替org.apache.tomcat.jdbc.pool.DataSource
    這里我們通過dataSourceJNDI=DerbyXA1屬性鏈接這兩個(gè)數(shù)據(jù)源。這兩個(gè)數(shù)據(jù)源都不得不存在同一個(gè)命名空間,在我們的例子中,是jdbc命名空間。

     

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

    如果你加入一個(gè)

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

    這是一個(gè)有趣的現(xiàn)象當(dāng)你處理 XADataSources。你可以把返回的對象轉(zhuǎn)換為java.sql.Connection對象或者javax.sql.XAConnection對象,并且對同一個(gè)對象的兩個(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ū)動封裝了java.sql.Connection/javax.sql.XAConnection或者數(shù)據(jù)源本身就是一個(gè)攔截器。攔截器以java.lang.reflect.InvocationHandler接口為基礎(chǔ)。攔截器是一個(gè)繼承自org.apache.tomcat.pool.jdbc.JdbcInterceptor的類。

    在本文中,我們將介紹如果配置攔截器。在我們下一篇文章,我們將介紹如果實(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è)短小的名稱,比如ConnectionState,如果這個(gè)攔截器定義在org.apache.tomcat.jdbc.pool.interceptor 包中。

     

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

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

    連接狀態(tài)

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

    •        autoCommit
    •         readOnly
    •         transactionIsolation
    •         catalog

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

    •         defaultAutoCommit
    •         defaultReadOnly
    •         defaultTransactionIsolation
    •         defaultCatalog

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

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

    Statement Finalizer

    java代碼在使用java.sql對象后需要清除和釋放使用過的資源。

    一個(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)連接沒有正確關(guān)閉的情況。

     

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

    獲得真正的JDBC連接

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

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

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

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

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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 五月婷婷免费视频| 国产亚洲视频在线观看网址| 亚洲国产午夜精品理论片| 久久亚洲国产最新网站| 亚洲av乱码一区二区三区按摩 | 亚洲av无码不卡一区二区三区| 亚洲成年轻人电影网站www| 亚洲成a人片在线看| 99亚洲乱人伦aⅴ精品| aa级女人大片喷水视频免费| 91高清免费国产自产拍2021| 我想看一级毛片免费的| 亚洲免费视频一区二区三区| 亚洲精品在线观看视频| 亚洲中文字幕无码久久| 国产在线观a免费观看| 无码国产精品一区二区免费式影视 | v片免费在线观看| 久久一本岛在免费线观看2020| 日韩欧美一区二区三区免费观看| 又粗又黄又猛又爽大片免费| 亚洲av永久无码精品网站| 欧洲 亚洲 国产图片综合| 一级黄色毛片免费看| 免费国产黄网站在线观看可以下载| 成在人线AV无码免费| 国产亚洲一区二区三区在线不卡| 亚洲福利一区二区| 美女免费精品高清毛片在线视| 免费在线观看一级片| 成人免费毛片视频| 亚洲精品无码久久千人斩| 亚洲av无码片区一区二区三区| 一级成人毛片免费观看| 日韩中文字幕精品免费一区| 亚洲美女高清一区二区三区| 亚洲人成在线精品| 久久精品成人免费观看97| 毛片免费全部免费观看| 精品亚洲综合久久中文字幕| 亚洲欧美乱色情图片|