JDBC 連接池 org.apache.tomcat.jdbc.pool
是 Apache Commons DBCP 連接池的一種替換或備選方案。
那究竟為何需要一個新的連接池?
原因如下:
NoSuchMethodException
異常。javax.sql.PooledConnection
接口獲取底層連接。Tomcat JDBC 連接池還具有一些其他連接池實現(xiàn)所沒有的特點:
java.sql
/javax.sql
接口的 JDK 版本沒有任何關系。Future<Connection>
。ResetAbandonedTimer
來實現(xiàn)的。removeAbandonedTimeout
,但卻不需要采取任何行為,只需要報告信息即可。通過 suspectTimeout
屬性來實現(xiàn)。java.sql.Driver
、javax.sql.DataSource
或 javax.sql.XADataSource
獲取連接。通過 dataSource
與 dataSourceJNDI
屬性實現(xiàn)這一點。對于熟悉 Commons DBCP 的人來說,轉(zhuǎn)而使用 Tomcat 連接池是非常簡單的事。從其他連接池轉(zhuǎn)換過來也非常容易。
除了其他多數(shù)連接池能夠提供的功能外,Tomcat 連接池還提供了一些附加功能:
initSQL
當連接創(chuàng)建后,能夠執(zhí)行一個 SQL 語句(只執(zhí)行一次)。validationInterval
恰當?shù)卦谶B接上運行驗證,同時又能避免太多頻繁地執(zhí)行驗證。jdbcInterceptors
靈活并且可插拔的攔截器,能夠?qū)Τ剡M行各種自定義,執(zhí)行各種查詢,處理結(jié)果集。下文將予以詳述。fairQueue
將 fair 標志設為 true,以達成線程公平性,或使用異步連接獲取。在Tomcat JDBC 文檔中,Tomcat 連接池被配置為一個資源。唯一的區(qū)別在于,你必須指定 factory
屬性,并將其值設為 org.apache.tomcat.jdbc.pool.DataSourceFactory
。
連接池只有一個從屬文件,tomcat-juli.jar。要想在使用 bean 實例化的單一項目中使用池,實例化的 Bean 為org.apache.tomcat.jdbc.pool.DataSource
。下文講到將連接池配置為 JNDI 資源時會涉及到同一屬性,也是用來將數(shù)據(jù)源配置成 bean 的。
連接池對象暴露了一個可以被注冊的 MBean。為了讓連接池對象創(chuàng)建 MBean,jmxEnabled
標志必須設為 true。這并不是說連接池會注冊到 MBean 服務器。在像 Tomcat 這樣的容器中,Tomcat 本身注冊就在 MBean 服務器上注冊了 DataSource。org.apache.tomcat.jdbc.pool.DataSource
對象會注冊實際的連接池 MBean。如果你在容器外運行,可以將 DataSource 注冊在任何你指定的對象名下,然后將這種注冊傳播到底層池。要想這樣做,你必須調(diào)用 mBeanServer.registerMBean(dataSource.getPool().getJmxPool(),objectname)
。在調(diào)用之前,一定要保證通過調(diào)用 dataSource.createPool()
創(chuàng)建了池。
為了能夠順暢地在 Commons DBCP 與 Tomcat JDBC 連接池 之間轉(zhuǎn)換,大多數(shù)屬性名稱及其含義都是相同的。
屬性 | 描述 |
---|---|
factory
|
必需的屬性,其值應為 org.apache.tomcat.jdbc.pool.DataSourceFactory
|
type
|
類型應為 javax.sql.DataSource 或 javax.sql.XADataSource 。
根據(jù)類型,將創(chuàng)建 org.apache.tomcat.jdbc.pool.DataSource 或 org.apache.tomcat.jdbc.pool.XADataSource 。 |
系統(tǒng)屬性作用于 JVM 范圍,影響創(chuàng)建于 JVM 內(nèi)的所有池。
屬性 | 描述 |
---|---|
org.apache.tomcat.jdbc.pool.onlyAttemptCurrentClassLoader
|
布爾值,默認為 false ??刂苿討B(tài)類(如JDBC 驅(qū)動、攔截器、驗證器)的加載。如果采用默認值,池會首先利用當前類加載器(比如已經(jīng)加載池類的類加載器)加載類;如果類加載失敗,則嘗試利用線程上下文加載器加載。取值為 true 時,會向后兼容 Apache Tomcat 8.0.8 及更早版本,只會采用當前類加載器。如果未設置,則取默認值。 |
屬性 | 描述 |
---|---|
defaultAutoCommit
|
(布爾值)連接池所創(chuàng)建的連接默認自動提交狀態(tài)。如果未設置,則默認采用 JDBC 驅(qū)動的缺省值(如果未設置,則不會調(diào)用 setAutoCommit 方法)。 |
defaultReadOnly
|
(布爾值)連接池所創(chuàng)建的連接默認只讀狀態(tài)。如果未設置,將不會調(diào)用 setReadOnly 方法。(有些驅(qū)動并不支持只讀模式,比如:informix) |
defaultTransactionIsolation
|
(字符串)連接池所創(chuàng)建的連接的默認事務隔離狀態(tài)。取值范圍為:(參考 javadoc)
NONE
READ_COMMITTED
READ_UNCOMMITTED
REPEATABLE_READ
SERIALIZABLE
如果未設置該值,則不會調(diào)用任何方法,默認為 JDBC 驅(qū)動。 |
defaultCatalog
|
(字符串)連接池所創(chuàng)建的連接的默認catalog。 |
driverClassName
|
(字符串)所要使用的 JDBC 驅(qū)動的完全限定的 Java 類名。該驅(qū)動必須能從與 tomcat-jdbc.jar 同樣的類加載器訪問 |
username
|
(字符串)傳入 JDBC 驅(qū)動以便建立連接的連接用戶名。注意,DataSource.getConnection(username,password) 方法默認不會使用傳入該方法內(nèi)的憑證,但會使用這里的配置信息??蓞⒖?alternateUsernameAllowed 了解更多詳情。 |
password
|
(字符串)傳入 JDBC 驅(qū)動以便建立連接的連接密碼。注意,DataSource.getConnection(username,password) 方法默認不會使用傳入該方法內(nèi)的憑證,但會使用這里的配置信息??蓞⒖?alternateUsernameAllowed 了解更多詳情。 |
maxActive
|
(整形值)池同時能分配的活躍連接的最大數(shù)目。默認為 100 。 |
maxIdle
|
(整型值)池始終都應保留的連接的最大數(shù)目。默認為 maxActive:100 。會周期性檢查空閑連接(如果啟用該功能),留滯時間超過 minEvictableIdleTimeMillis 的空閑連接將會被釋放。(請參考 testWhileIdle ) |
minIdle
|
(整型值)池始終都應保留的連接的最小數(shù)目。如果驗證查詢失敗,則連接池會縮減該值。默認值取自 initialSize:10 (請參考 testWhileIdle )。 |
initialSize
|
(整型值)連接器啟動時創(chuàng)建的初始連接數(shù)。默認為 10 。 |
maxWait
|
(整型值)在拋出異常之前,連接池等待(沒有可用連接時)返回連接的最長時間,以毫秒計。默認為 30000 (30 秒) |
testOnBorrow
|
(布爾值)默認值為 false 。從池中借出對象之前,是否對其進行驗證。如果對象驗證失敗,將其從池中清除,再接著去借下一個。注意:為了讓 true 值生效,validationQuery 參數(shù)必須為非空字符串。為了實現(xiàn)更高效的驗證,可以采用 validationInterval 。 |
testOnReturn
|
(布爾值)默認值為 false 。將對象返回池之前,是否對齊進行驗證。注意:為了讓 true 值生效,validationQuery 參數(shù)必須為非空字符串。 |
testWhileIdle
|
(布爾值)是否通過空閑對象清除者(如果存在的話)驗證對象。如果對象驗證失敗,則將其從池中清除。注意:為了讓 true 值生效,validationQuery 參數(shù)必須為非空字符串。該屬性默認值為 false ,為了運行池的清除/測試線程,必須設置該值。(另請參閱 timeBetweenEvictionRunsMillis ) |
validationQuery
|
(字符串)在將池中連接返回給調(diào)用者之前,用于驗證這些連接的 SQL 查詢。如果指定該值,則該查詢不必返回任何數(shù)據(jù),只是不拋出 SQLException 異常。默認為 null 。實例值為:SELECT 1 (MySQL) select 1 from dual (Oracle) SELECT 1 (MySQL Server)。 |
validationQueryTimeout
|
(整型值)連接驗證失敗前的超時時間(以秒計)。通過在執(zhí)行 validationQuery 的語句上調(diào)用 java.sql.Statement.setQueryTimeout(seconds) 來實現(xiàn)。池本身并不會讓查詢超時,完全是由 JDBC 來強制實現(xiàn)。若該值小于或等于 0,則禁用該功能。默認為 -1 。 |
validatorClassName
|
(字符串)實現(xiàn) org.apache.tomcat.jdbc.pool.Validator 接口并提供了一個無參(可能是隱式的)構(gòu)造函數(shù)的類名。如果指定該值,將通過該類來創(chuàng)建一個 Validator 實例來驗證連接,代替任何驗證查詢。默認為 null ,范例值為:com.mycompany.project.SimpleValidator 。 |
timeBetweenEvictionRunsMillis
|
(整型值)空閑連接驗證/清除線程運行之間的休眠時間(以毫秒計)。不能低于 1 秒。該值決定了我們檢查空閑連接、廢棄連接的頻率,以及驗證空閑連接的頻率。默認為 5000 (5 秒) |
numTestsPerEvictionRun
|
(整型值)Tomcat JDBC 連接池沒有用到這個屬性。 |
minEvictableIdleTimeMillis
|
(整型值)在被確定應被清除之前,對象在池中保持空閑狀態(tài)的最短時間(以毫秒計)。默認為 60000 (60 秒) |
accessToUnderlyingConnectionAllowed
|
(布爾值)沒有用到的屬性??梢栽跉w入池內(nèi)的連接上調(diào)用 unwrap 來訪問。參閱 javax.sql.DataSource 接口的相關介紹,或者通過反射調(diào)用 getConnection ,或者將對象映射為 javax.sql.PooledConnection 。 |
removeAbandoned
|
(布爾值)該值為標志(Flag)值,表示如果連接時間超出了 removeAbandonedTimeout ,則將清除廢棄連接。如果該值被設置為 true ,則如果連接時間大于 removeAbandonedTimeout ,該連接會被認為是廢棄連接,應予以清除。若應用關閉連接失敗時,將該值設為 true 能夠恢復該應用的數(shù)據(jù)庫連接。另請參閱 logAbandoned 。默認值為 false 。 |
removeAbandonedTimeout
|
(整型值)在廢棄連接(仍在使用)可以被清除之前的超時秒數(shù)。默認為 60 (60 秒)。應把該值設定為應用可能具有的運行時間最長的查詢。 |
logAbandoned
|
(布爾值)標志能夠針對丟棄連接的應用代碼,進行堆棧跟蹤記錄。由于生成堆棧跟蹤,對廢棄連接的日志記錄會增加每一個借取連接的開銷。默認為 false
|
connectionProperties
|
(字符串)在建立新連接時,發(fā)送給 JDBC 驅(qū)動的連接屬性。字符串格式必須為:[propertyName=property;]*。注意:user 與 password 屬性會顯式傳入,因此這里并不需要包括它們。默認為 null。
|
poolPreparedStatements
|
(布爾值)未使用的屬性 |
maxOpenPreparedStatements
|
(整型值)未使用的屬性 |
屬性 | 描述 |
---|---|
initSQL
|
字符串值。當連接第一次創(chuàng)建時,運行的自定義查詢。默認值為 null 。 |
jdbcInterceptors
|
字符串。繼承自類 org.apache.tomcat.jdbc.pool.JdbcInterceptor 的子類類名列表,由分號分隔。關于格式及范例,可參見下文的配置 JDBC 攔截器。
這些攔截器將會插入到 java.sql.Connection 對象的操作隊列中。
預定義的攔截器有: org.apache.tomcat.jdbc.pool.interceptor
ConnectionState ——記錄自動提交、只讀、catalog以及事務隔離級別等狀態(tài)。org.apache.tomcat.jdbc.pool.interceptor
StatementFinalizer ——記錄打開的語句,并當連接返回池后關閉它們。有關更多預定義攔截器的詳盡描述,可參閱JDBC 攔截器 |
validationInterval
|
長整型值。為避免過度驗證而設定的頻率時間值(以秒計)。最多以這種頻率運行驗證。如果連接應該進行驗證,但卻沒能在此間隔時間內(nèi)得到驗證,則會重新對其進行驗證。默認為 30000 (30 秒)。 |
jmxEnabled
|
布爾值。是否利用 JMX 注冊連接池。默認為 true 。 |
fairQueue
|
布爾值。假如想用真正的 FIFO 方式公平對待 getConnection 調(diào)用,則取值為 true 。對空閑連接列表將采用 org.apache.tomcat.jdbc.pool.FairBlockingQueue 實現(xiàn)。默認值為 true 。如果想使用異步連接獲取功能,則必須使用該標志。
設置該標志可保證線程能夠按照連接抵達順序來接收連接。 在性能測試時,鎖及鎖等待的實現(xiàn)方式有很大差異。當 fairQueue=true 時,根據(jù)所運行的操作系統(tǒng),存在一個決策過程。假如系統(tǒng)運行在 Linux 操作系統(tǒng)(屬性 os.name = linux )上,為了禁止這個 Linux 專有行為,但仍想使用公平隊列,那么只需在連接池類加載之前,將 org.apache.tomcat.jdbc.pool.FairBlockingQueue.ignoreOS=true 添加到系統(tǒng)屬性上。 |
abandonWhenPercentageFull
|
整型值。除非使用中連接的數(shù)目超過 abandonWhenPercentageFull 中定義的百分比,否則不會關閉并報告已廢棄的連接(因為超時)。取值范圍為 0-100。默認值為 0,意味著只要達到 removeAbandonedTimeout ,就應關閉連接。 |
maxAge
|
長整型值。連接保持時間(以毫秒計)。當連接要返回池中時,連接池會檢查是否達到 now - time-when-connected > maxAge 的條件,如果條件達成,則關閉該連接,不再將其返回池中。默認值為 0 ,意味著連接將保持開放狀態(tài),在將連接返回池中時,不會執(zhí)行任何年齡檢查。 |
useEquals
|
布爾值。如果想讓 ProxyConnection 類使用 String.equals ,則將該值設為 true ;若想在對比方法名稱時使用 == ,則應將其設為 false 。該屬性不能用于任何已添加的攔截器中,因為那些攔截器都是分別配置的。默認值為 true 。 |
suspectTimeout
|
整型值。超時時間(以秒計)。默認值為 0 。
類似于 removeAbandonedTimeout ,但不會把連接當做廢棄連接從而有可能關閉連接。如果 logAbandoned 設為 true ,它只會記錄下警告。如果該值小于或等于 0,則不會執(zhí)行任何懷疑式檢查。如果超時值大于 0,而連接還沒有被廢棄,或者廢棄檢查被禁用時,才會執(zhí)行懷疑式檢查。如果某個連接被懷疑到,則記錄下 WARN 信息并發(fā)送一個 JMX 通知。 |
rollbackOnReturn
|
布爾值。如果 autoCommit==false ,那么當連接返回池中時,池會在連接上調(diào)用回滾方法,從而終止事務。默認值為 false 。 |
commitOnReturn
|
布爾值。如果 autoCommit==false ,那么當連接返回池中時,池會在連接上調(diào)用提交方法,從而完成事務;如果 rollbackOnReturn==true ,則忽略該屬性。默認值為 false 。 |
alternateUsernameAllowed
|
布爾值。出于性能考慮,JDBC 連接池默認會忽略 DataSource.getConnection(username,password) 調(diào)用,只返回之前池化的具有全局配置屬性 username 和 password 的連接。
但經(jīng)過配置,連接池還可以允許使用不同的憑證來請求每一個連接。為了啟用這項在 DataSource.getConnection(username,password) 調(diào)用中描述的功能,只需將 alternateUsernameAllowed 設為 true 。
如果你請求一個連接,憑證為 user 1/password 1,而連接之前使用的是 user 2/password 2 憑證,那么連接將被關閉,重新利用請求的憑證來開啟。按照這種方式,池的容量始終以全局級別管理,而不是限于模式(schema)級別。 默認值為 false 。
該屬性作為一個改進方案,被添加到了 bug 50025 中。 |
dataSource
|
(javax.sql.DataSource)將數(shù)據(jù)源注入連接池,從而使池利用數(shù)據(jù)源來獲取連接,而不是利用 java.sql.Driver 接口來建立連接。它非常適于使用數(shù)據(jù)源(而非連接字符串)來池化 XA 連接或者已建立的連接時。默認值為 null 。 |
dataSourceJNDI
|
字符串。在 JNDI 中查找的數(shù)據(jù)源的 JNDI 名稱,隨后將用于建立數(shù)據(jù)庫連接。參看 datasource 屬性的介紹。默認值為 null 。 |
useDisposableConnectionFacade
|
布爾值。如果希望在連接上放上一個門面對象,從而使連接在關閉后無法重用,則要將值設為 true 。這能防止線程繼續(xù)引用一個已被關閉的連接,并繼續(xù)在連接上查詢。默認值為 true 。 |
logValidationErrors
|
布爾值。設為 true 時,能將驗證階段的錯誤記錄到日志文件中,錯誤會被記錄為 SEVERE??紤]到了向后兼容性,默認值為 false 。 |
propagateInterruptState
|
布爾值。傳播已中斷的線程(還沒有清除中斷狀態(tài))的中斷狀態(tài)??紤]到了向后兼容性,默認值為 false 。 |
ignoreExceptionOnPreLoad
|
布爾值。在初始化池時,是否忽略連接創(chuàng)建錯誤。取值為 true 時表示忽略;設為 false 時,拋出異常,從而宣告池初始化失敗。默認值為 false 。 |
要想看看攔截器使用方法的具體范例,可以看看 org.apache.tomcat.jdbc.pool.interceptor.ConnectionState
。這個簡單的攔截器緩存了三個屬性:autoCommit
、readOnly
、transactionIsolation
,為的是避免系統(tǒng)與數(shù)據(jù)庫之間無用的往返。
當需求增加時,姜維連接池核心增加更多的攔截器。歡迎貢獻你的才智!
攔截器當然并不局限于 java.sql.Connection
,當然也可以對方法調(diào)用的任何結(jié)果進行包裝。你可以構(gòu)建查詢性能分析器,以便當查詢運行時間超過預期時間時提供 JMX 通知。
JDBC 攔截器是通過 jdbcInterceptor 屬性來配置的。該屬性值包含一列由分號分隔的類名。如果這些類名非完全限定,就會在它們的前面加上 org.apache.tomcat.jdbc.pool.interceptor.
前綴。
范例:
jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState; org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
它實際上等同于:
jdbcInterceptors="ConnectionState;StatementFinalizer"
攔截器也同樣有屬性。攔截器的屬性指定在類名后的括號里,如果設置多個屬性,則用逗號分隔開。
范例:
jdbcInterceptors="ConnectionState;StatementFinalizer(useEquals=true)"
系統(tǒng)會自動忽略屬性名稱、屬性值以及類名前后多余的空格字符。
所有攔截器的抽象基類,無法實例化。
屬性 | 描述 |
---|---|
useEquals | (布爾值)如果希望 ProxyConnection 類使用 String.equals ,則設為 true;當希望在對比方法名時使用 == ,則設為 false 。默認為 true 。 |
它能為下列屬性緩存連接:autoCommit
、readOnly
、transactionIsolation
及 catalog
。這是一種性能增強功能,當利用已設定的值來調(diào)用 getter 與 setter 時,它能夠避免往返數(shù)據(jù)庫。
跟蹤所有使用 createStatement
、prepareStatement
或 prepareCall
的語句,當連接返回池后,關閉這些語句。
屬性 | 描述 |
---|---|
trace | (以字符串形式表示的布爾值)對未關閉語句進行跟蹤。當啟用跟蹤且連接被關閉時,如果相關語句沒有關閉,則攔截器會記錄所有的堆棧跟蹤。默認值為 false 。 |
緩存連接中的 PreparedStatement
或 CallableStatement
實例。
它會針對每個連接對這些語句進行緩存,然后計算池中所有連接的整體緩存數(shù),如果緩存數(shù)超過了限制 max
,就不再對隨后的語句進行緩存,而是直接關閉它們。
屬性 | 描述 |
---|---|
prepared
|
(以字符串形式表示的布爾值)對使用 prepareStatement 調(diào)用創(chuàng)建的 PreparedStatement 實例進行緩存。默認為 true
|
callable
|
(以字符串形式表示的布爾值)對使用 prepareCall 調(diào)用創(chuàng)建的 CallableStatement 實例進行緩存。默認為 false
|
max
|
(以字符串形式表示的整型值)連接池中的緩存語句的數(shù)量限制。默認為 50
|
請參看 48392。攔截器會包裝語句和結(jié)果集,從而防止對使用了 ResultSet.getStatement().getConnection()
和 Statement.getConnection()
方法的實際連接進行訪問。
當新語句創(chuàng)建時,自動調(diào)用 java.sql.Statement.setQueryTimeout(seconds)
。池本身并不會讓查詢超時,完全是依靠 JDBC 驅(qū)動來強制查詢超時。
屬性 | 描述 |
---|---|
queryTimeout
|
(以字符串形式表示的整型值)查詢超時的毫秒數(shù)。默認為 1000 毫秒。 |
當查詢超過失敗容差值時,記錄查詢性能并發(fā)布日志項目。使用的日志級別為 WARN
。
屬性 | 描述 |
---|---|
threshold
|
(以字符串形式表示的整型值)查詢應超時多少毫秒才發(fā)布日志警告。默認為 1000 毫秒 |
maxQueries
|
(以字符串形式表示的整型值)為保留內(nèi)存空間,所能記錄的最大查詢數(shù)量。默認為 1000
|
logSlow
|
(以字符串形式表示的布爾值)如果想記錄較慢的查詢,設為 true 。默認為 true
|
logFailed
|
(以字符串形式表示的布爾值)如果想記錄失敗查詢,設為 true 。默認為 true
|
這是對 SlowQueryReport
的擴展,除了發(fā)布日志項目外,它還發(fā)布 JMX 通知,以便監(jiān)視工具作出相關反應。該類從其父類繼承了所有屬性。它使用了 Tomcat 的 JMX 引擎,所以在 Tomcat 容器外部是無效的。使用該類時,默認情況下,是通過 ConnectionPool
MBean 來發(fā)送 JMX 通知。如果 notifyPool=false
,則 SlowQueryReportJmx
也可以注冊一個
MBean。
屬性 | 描述 |
---|---|
notifyPool
|
(以字符串形式表示的布爾值)如果希望用 SlowQueryReportJmx MBean 發(fā)送 JMX 通知,則設為 false 。默認為 true
|
objectName
|
字符串。定義一個有效的 javax.management.ObjectName 字符串,用于將這一對象注冊到平臺所用的 mbean 服務器上。默認值為 null ??梢允褂?tomcat.jdbc:type=org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx,name=the-name-of-the-pool 來注冊對象。 |
當連接簽出池中后,廢棄計時器即開始計時。這意味著如果超時為 30 秒,而你使用連接運行了 10 個 10秒的查詢,那么它就會被標為廢棄,并可能依靠 abandonWhenPercentageFull
屬性重新聲明。每次成功地在連接上執(zhí)行操作或執(zhí)行查詢時,該攔截器就會重設簽出計時器。
其他 JDBC 用途的 Tomcat 配置范例可以參考 相關的 Tomcat 文檔。
下面這個簡單的范例展示了如何創(chuàng)建并使用數(shù)據(jù)源:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
public class SimplePOJOExample {
public static void main(String[] args) throws Exception {
PoolProperties p = new PoolProperties();
p.setUrl("jdbc:mysql://localhost:3306/mysql");
p.setDriverClassName("com.mysql.jdbc.Driver");
p.setUsername("root");
p.setPassword("password");
p.setJmxEnabled(true);
p.setTestWhileIdle(false);
p.setTestOnBorrow(true);
p.setValidationQuery("SELECT 1");
p.setTestOnReturn(false);
p.setValidationInterval(30000);
p.setTimeBetweenEvictionRunsMillis(30000);
p.setMaxActive(100);
p.setInitialSize(10);
p.setMaxWait(10000);
p.setRemoveAbandonedTimeout(60);
p.setMinEvictableIdleTimeMillis(30000);
p.setMinIdle(10);
p.setLogAbandoned(true);
p.setRemoveAbandoned(true);
p.setJdbcInterceptors(
"org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"+
"org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
DataSource datasource = new DataSource();
datasource.setPoolProperties(p);
Connection con = null;
try {
con = datasource.getConnection();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("select * from user");
int cnt = 1;
while (rs.next()) {
System.out.println((cnt++)+". Host:" +rs.getString("Host")+
" User:"+rs.getString("User")+" Password:"+rs.getString("Password"));
}
rs.close();
st.close();
} finally {
if (con!=null) try {con.close();}catch (Exception ignore) {}
}
}
}
下例展示了如何為 JNDI 查找配置資源。
<Resource name="jdbc/TestDB"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
testWhileIdle="true"
testOnBorrow="true"
testOnReturn="false"
validationQuery="SELECT 1"
validationInterval="30000"
timeBetweenEvictionRunsMillis="30000"
maxActive="100"
minIdle="10"
maxWait="10000"
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="password"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mysql"/>
Tomcat JDBC 連接池支持異步連接獲取,無需為池庫添加任何額外線程。這是通過在數(shù)據(jù)源上添加一個方法 Future<Connection> getConnectionAsync()
來實現(xiàn)的。為了使用異步獲取,必須滿足兩個條件:
failQueue
屬性設為 true
。org.apache.tomcat.jdbc.pool.DataSource
。下例就使用了異步獲取功能:
Connection con = null;
try {
Future<Connection> future = datasource.getConnectionAsync();
while (!future.isDone()) {
System.out.println("Connection is not yet available. Do some background work");
try {
Thread.sleep(100); //simulate work
}catch (InterruptedException x) {
Thread.currentThread().interrupt();
}
}
con = future.get(); //should return instantly
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("select * from user");
對于啟用、禁止或修改特定連接或其組件的功能而言,使用攔截器無疑是一種非常強大的方式。There are many different use cases for when interceptors are useful。默認情況下,基于性能方面的考慮,連接池是無狀態(tài)的。連接池本身所插入的狀態(tài)是 defaultAutoCommit
、defaultReadOnly
、defaultTransactionIsolation
,或 defaultCatalog
(如果設置了這些狀態(tài))。這
4 個狀態(tài)只有在連接創(chuàng)建時才設置。無論這些屬性是否在連接使用期間被修改,池本身都不能重置它們。
攔截器必須擴展自 org.apache.tomcat.jdbc.pool.JdbcInterceptor
類。該類相當簡單,你必須利用一個無參數(shù)構(gòu)造函數(shù)。
public JdbcInterceptor() {
}
當從連接池借出一個連接時,攔截器能夠通過實現(xiàn)以下方法,初始化這一事件或以一些其他形式來響應該事件。
public abstract void reset(ConnectionPool parent, PooledConnection con);
上面這個方法有兩個參數(shù),一個是連接池本身的引用 ConnectionPool parent
,一個是底層連接的引用 PooledConnection con
。
當調(diào)用 java.sql.Connection
對象上的方法時,會導致以下方法被調(diào)用:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Method method
是被調(diào)用的實際方法,Object[] args
是參數(shù)。通過觀察下面這個非常簡單的例子,我們可以解釋如果當連接已經(jīng)關閉時,如何讓 java.sql.Connection.close()
的調(diào)用變得無用。
if (CLOSE_VAL==method.getName()) {
if (isClosed()) return null; //noop for already closed.
}
return super.invoke(proxy,method,args);
當連接池開啟或關閉時,你可以得到相關通知。可能每個攔截器類只通知一次,即使它是一個實例方法。也可能使用當前未連接到池中的攔截器來通知你。
public void poolStarted(ConnectionPool pool) {
}
public void poolClosed(ConnectionPool pool) {
}
當重寫這些方法時,如果你擴展自 JdbcInterceptor
之外的類,不要忘記調(diào)用超類。
攔截器可以通過 jdbcInterceptors
屬性或 setJdbcInterceptors
方法來配置。攔截器也可以有屬性,可以通過如下方式來配置:
String jdbcInterceptors=
"org.apache.tomcat.jdbc.pool.interceptor.ConnectionState(useEquals=true,fast=yes)"
既然攔截器也有屬性,那么你也可以讀取其中的屬性值。你可以重寫 setProperties
方法。
public void setProperties(Map<String, InterceptorProperty> properties) {
super.setProperties(properties);
final String myprop = "myprop";
InterceptorProperty p1 = properties.get(myprop);
if (p1!=null) {
setMyprop(Long.parseLong(p1.getValue()));
}
}
連接池圍繞實際的連接創(chuàng)建包裝器,為的是能夠正確地池化。同樣,為了執(zhí)行特定的功能,我們也可以在這些包裝器中創(chuàng)建攔截器。如果不需要獲取實際的連接,可以使用 javax.sql.PooledConnection
接口。
Connection con = datasource.getConnection();
Connection actual = ((javax.sql.PooledConnection)con).getConnection();
下面利用 1.6 來構(gòu)建 JDBC 連接池代碼,但它也可以向后兼容到 1.5 運行時環(huán)境。為了單元測試,使用 1.6 或更高版本。
更多的關于 JDBC 用途的 Tomcat 配置范例可參看 [Tomcat 文檔]()。
構(gòu)建非常簡單。池依賴于 tomcat-juli.jar
,在這種情況下,需要 SlowQueryReportJmx
。
javac -classpath tomcat-juli.jar \
-d . \
org/apache/tomcat/jdbc/pool/*.java \
org/apache/tomcat/jdbc/pool/interceptor/*.java \
org/apache/tomcat/jdbc/pool/jmx/*.java
構(gòu)建文件位于 Tomcat 的源代碼倉庫中。
為了方便起見,在通過簡單構(gòu)建命令生成所需文件的地方也包含了一個構(gòu)建文件。
ant download (downloads dependencies)
ant build (compiles and generates .jar files)
ant dist (creates a release package)
ant test (runs tests, expects a test database to be setup)
系統(tǒng)針對 Maven 構(gòu)建進行組織,但是沒有生成發(fā)布組件,只有庫本身。
更多建議: