Tomcat 7 的JDBC連接池實現(xiàn)類為org.apache.tomcat.jdbc.pool
,作為替換commons-dbcp
的方案。
替換commons-dbcp
的原因如下:
commons-dbcp
是單線程的,為了線程安全,就要瑣住整個連接池,查詢驗證階段也要瑣住整個連接池。
commons-dbcp
速度慢,性能差,多CPU的環(huán)境下單線程運行,不支持高并發(fā),在JAVA 6中也不能解決速度和并發(fā)的問題。
commons-dbcp
實現(xiàn)復雜,超過60個類。tomcat-jdbc-pool
核心只有8個類,修改更加簡單,只需運行連接池本身,易測試。
commons-dbcp
應(yīng)用靜態(tài)接口,就意味著并不能用JDK 1.6編譯它,在JDK 1.6/1.7中運行時,即使驅(qū)動程序支持,所有沒有實現(xiàn)的方法也都會拋出NoSuchMethodException
異常。
commons-dbcp
幾乎停滯,很少更新。
作為一個連接池的簡單實現(xiàn)不值得重寫超過60個類。
Tomcat jdbc連接池實現(xiàn)了一個commons-dbcp
沒有的公平算法,并且比commons-dbcp
性能更好。
Tomcat jdbc連接池實現(xiàn)了異步獲取連接,也不需增加額外的線程。
Tomcat jdbc連接池是一個Tomcat的模塊,依賴于Tomcat JULI(Tomcat日志框架)
使用javax.sql.PooledConnection
接口獲取連接。
饑餓算法。如果連接池空了,同時一個線程要獲得連接,當一個連接返回到連接池,連接池會將正確的線程喚醒。
除了commons-dbcp
連接池,還有其它可以選擇的方案,如c3p0
,bonecp
等,與這些連接池實現(xiàn)相比,Tomcat jdbc pool更突出的功能體現(xiàn)在:
支持多核系統(tǒng),提供更好的高并發(fā)性能。
接口動態(tài)實現(xiàn),運行時環(huán)境支持java.sql
和javax.sql
接口,可以使用低版本JDK編譯。
無需每次使用連接時都驗證連接,可以在獲取或返回連接時驗證,不用比設(shè)置的間隔時間更頻繁。
當數(shù)據(jù)庫連接建立時,一個可設(shè)置的查詢將運行一次。這對保持連接建立整個時間中的會話十分有用。
可以自定義攔截器增強功能??啥x攔截器來收集查詢統(tǒng)計,緩存會話狀態(tài),重新連接,重新查詢,緩存查詢結(jié)果等。
高性能
極其簡單,由于非常簡單的實現(xiàn),源程序行數(shù)和文件數(shù)很少,相比c3p0的200多個源程序文件,Tomcat jdbc只有8個核心源文件,關(guān)于連接池的部分只有4個文件。這樣更容易追溯和修改Bug。減少復雜性就是起初開發(fā)的一個焦點。
異步獲取連接,可將連接請求形成隊列,系統(tǒng)返回Future<Connection>
更好的空閑連接處理,應(yīng)用更優(yōu)化的算法調(diào)整連接池大小和連接的釋放。
用戶來決定當連接池滿了在什么時刻釋放連接,或者直接設(shè)置一個超時的閥值。
釋放連接定時器將會在查詢時重置。允許一個使用很長時間的連接不超時。這個功能由ResetAbandonedTimer
完成。
在連接一定長時間后關(guān)閉連接。時間與返回連接池的時間相似。
當連接要被釋放時,將得到JMX通知并且記錄整個日志。這和removeAbandonedTimeout
相似,但是只輸出信息,不做任何操作。使用suspectTimeout
屬性完成設(shè)置。
可以從java.sql.Driver
,javax.sql.DataSource
或者javax.sql.XADataSource
中取得連接,使用dataSource
和dataSourceJNDI
屬性完成。
支持XA連接。
Java代碼
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) {}
}
}
}
<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"> 2 </resource>
異步獲取連接1.必須將fairQueue
設(shè)置為true
2.必須將數(shù)據(jù)源轉(zhuǎn)換為org.apache.tomcat.jdbc.pool.DataSource
Connection con = null; try { Future 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().interrupted(); } } con = future.get(); //should return instantly Statement st = con.createStatement(); ResultSet rs = st.executeQuery("select * from user");
聯(lián)系客服