Tomcat 7 的JDBC连接池实现类为org.apache.tomcat.jdbc.pool,作为替换commons-dbcp的方案。
替换commons-dbcp的原因如下:
commons-dbcp是单线程的,为了线程安全,就要琐住整个连接池,查询验证阶段也要琐住整个连接池。
commons-dbcp速度慢,性能差,多CPU的环境下单线程运行,不支持高并发,在JAVA 6中也不能解决速度和并发的问题。
commons-dbcp实现复杂,超过60个类。tomcat-jdbc-pool核心只有8个类,修改更加简单,只需运行连接池本身,易测试。
commons-dbcp应用静态接口,就意味着并不能用JDK 1.6编译它,在JDK 1.6/1.7中运行时,即使驱动程序支持,所有没有实现的方法也都会抛出NoSuchMethodException异常。
commons-dbcp几乎停滞,很少更新。
作为一个连接池的简单实现不值得重写超过60个类。
Tomcat jdbc连接池实现了一个commons-dbcp没有的公平算法,并且比commons-dbcp性能更好。
Tomcat jdbc连接池实现了异步获取连接,也不需增加额外的线程。
Tomcat jdbc连接池是一个Tomcat的模块,依赖于Tomcat JULI(Tomcat日志框架)
使用javax.sql.PooledConnection接口获取连接。
饥饿算法。如果连接池空了,同时一个线程要获得连接,当一个连接返回到连接池,连接池会将正确的线程唤醒。
除了commons-dbcp连接池,还有其它可以选择的方案,如c3p0,bonecp等,与这些连接池实现相比,Tomcat jdbc pool更突出的功能体现在:
支持多核系统,提供更好的高并发性能。
接口动态实现,运行时环境支持java.sql和javax.sql接口,可以使用低版本JDK编译。
无需每次使用连接时都验证连接,可以在获取或返回连接时验证,不用比设置的间隔时间更频繁。
当数据库连接建立时,一个可设置的查询将运行一次。这对保持连接建立整个时间中的会话十分有用。
可以自定义拦截器增强功能。可定义拦截器来收集查询统计,缓存会话状态,重新连接,重新查询,缓存查询结果等。
高性能
极其简单,由于非常简单的实现,源程序行数和文件数很少,相比c3p0的200多个源程序文件,Tomcat jdbc只有8个核心源文件,关于连接池的部分只有4个文件。这样更容易追溯和修改Bug。减少复杂性就是起初开发的一个焦点。
异步获取连接,可将连接请求形成队列,系统返回Future<Connection>
更好的空闲连接处理,应用更优化的算法调整连接池大小和连接的释放。
用户来决定当连接池满了在什么时刻释放连接,或者直接设置一个超时的阀值。
释放连接定时器将会在查询时重置。允许一个使用很长时间的连接不超时。这个功能由ResetAbandonedTimer完成。
在连接一定长时间后关闭连接。时间与返回连接池的时间相似。
当连接要被释放时,将得到JMX通知并且记录整个日志。这和removeAbandonedTimeout相似,但是只输出信息,不做任何操作。使用suspectTimeout属性完成设置。
可以从java.sql.Driver,javax.sql.DataSource或者javax.sql.XADataSource中取得连接,使用dataSource和dataSourceJNDI属性完成。
支持XA连接。
如何使用
单独使用
01 import java.sql.Connection;
02 import java.sql.ResultSet;
03 import java.sql.Statement;
04
05 import org.apache.tomcat.jdbc.pool.DataSource;
06 import org.apache.tomcat.jdbc.pool.PoolProperties;
07
08 public class SimplePOJOExample {
09
10 public static void main(String[] args) throws Exception {
11 PoolProperties p = new PoolProperties();
12 p.setUrl("jdbc:mysql://localhost:3306/mysql");
13 p.setDriverClassName("com.mysql.jdbc.Driver");
14 p.setUsername("root");
15 p.setPassword("password");
16 p.setJmxEnabled(true);
17 p.setTestWhileIdle(false);
18 p.setTestOnBorrow(true);
19 p.setValidationQuery("SELECT 1");
20 p.setTestOnReturn(false);
21 p.setValidationInterval(30000);
22 p.setTimeBetweenEvictionRunsMillis(30000);
23 p.setMaxActive(100);
24 p.setInitialSize(10);
25 p.setMaxWait(10000);
26 p.setRemoveAbandonedTimeout(60);
27 p.setMinEvictableIdleTimeMillis(30000);
28 p.setMinIdle(10);
29 p.setLogAbandoned(true);
30 p.setRemoveAbandoned(true);
31 p.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"+
32 "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
33 DataSource datasource = new DataSource();
34 datasource.setPoolProperties(p);
35
36 Connection con = null;
37 try {
38 con = datasource.getConnection();
39 Statement st = con.createStatement();
40 ResultSet rs = st.executeQuery("select * from user");
41 int cnt = 1;
42 while (rs.next()) {
43 System.out.println((cnt++)+". Host:" +rs.getString("Host")+
44 " User:"+rs.getString("User")+" Password:"+rs.getString("Password"));
45 }
46 rs.close();
47 st.close();
48 } finally {
49 if (con!=null) try {con.close();}catch (Exception ignore) {}
50 }
51 }
52
53 }
作为数据源在Tomcat中使用
1 <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设置为true
2.必须将数据源转换为org.apache.tomcat.jdbc.pool.DataSource
01 Connection con = null;
02 try {
03 Future future = datasource.getConnectionAsync();
04 while (!future.isDone()) {
05 System.out.println("Connection is not yet available. Do some background work");
06 try {
07 Thread.sleep(100); //simulate work
08 }catch (InterruptedException x) {
09 Thread.currentThread().interrupted();
10 }
11 }
12 con = future.get(); //should return instantly
13 Statement st = con.createStatement();
替换commons-dbcp的原因如下:
commons-dbcp是单线程的,为了线程安全,就要琐住整个连接池,查询验证阶段也要琐住整个连接池。
commons-dbcp速度慢,性能差,多CPU的环境下单线程运行,不支持高并发,在JAVA 6中也不能解决速度和并发的问题。
commons-dbcp实现复杂,超过60个类。tomcat-jdbc-pool核心只有8个类,修改更加简单,只需运行连接池本身,易测试。
commons-dbcp应用静态接口,就意味着并不能用JDK 1.6编译它,在JDK 1.6/1.7中运行时,即使驱动程序支持,所有没有实现的方法也都会抛出NoSuchMethodException异常。
commons-dbcp几乎停滞,很少更新。
作为一个连接池的简单实现不值得重写超过60个类。
Tomcat jdbc连接池实现了一个commons-dbcp没有的公平算法,并且比commons-dbcp性能更好。
Tomcat jdbc连接池实现了异步获取连接,也不需增加额外的线程。
Tomcat jdbc连接池是一个Tomcat的模块,依赖于Tomcat JULI(Tomcat日志框架)
使用javax.sql.PooledConnection接口获取连接。
饥饿算法。如果连接池空了,同时一个线程要获得连接,当一个连接返回到连接池,连接池会将正确的线程唤醒。
除了commons-dbcp连接池,还有其它可以选择的方案,如c3p0,bonecp等,与这些连接池实现相比,Tomcat jdbc pool更突出的功能体现在:
支持多核系统,提供更好的高并发性能。
接口动态实现,运行时环境支持java.sql和javax.sql接口,可以使用低版本JDK编译。
无需每次使用连接时都验证连接,可以在获取或返回连接时验证,不用比设置的间隔时间更频繁。
当数据库连接建立时,一个可设置的查询将运行一次。这对保持连接建立整个时间中的会话十分有用。
可以自定义拦截器增强功能。可定义拦截器来收集查询统计,缓存会话状态,重新连接,重新查询,缓存查询结果等。
高性能
极其简单,由于非常简单的实现,源程序行数和文件数很少,相比c3p0的200多个源程序文件,Tomcat jdbc只有8个核心源文件,关于连接池的部分只有4个文件。这样更容易追溯和修改Bug。减少复杂性就是起初开发的一个焦点。
异步获取连接,可将连接请求形成队列,系统返回Future<Connection>
更好的空闲连接处理,应用更优化的算法调整连接池大小和连接的释放。
用户来决定当连接池满了在什么时刻释放连接,或者直接设置一个超时的阀值。
释放连接定时器将会在查询时重置。允许一个使用很长时间的连接不超时。这个功能由ResetAbandonedTimer完成。
在连接一定长时间后关闭连接。时间与返回连接池的时间相似。
当连接要被释放时,将得到JMX通知并且记录整个日志。这和removeAbandonedTimeout相似,但是只输出信息,不做任何操作。使用suspectTimeout属性完成设置。
可以从java.sql.Driver,javax.sql.DataSource或者javax.sql.XADataSource中取得连接,使用dataSource和dataSourceJNDI属性完成。
支持XA连接。
如何使用
单独使用
01 import java.sql.Connection;
02 import java.sql.ResultSet;
03 import java.sql.Statement;
04
05 import org.apache.tomcat.jdbc.pool.DataSource;
06 import org.apache.tomcat.jdbc.pool.PoolProperties;
07
08 public class SimplePOJOExample {
09
10 public static void main(String[] args) throws Exception {
11 PoolProperties p = new PoolProperties();
12 p.setUrl("jdbc:mysql://localhost:3306/mysql");
13 p.setDriverClassName("com.mysql.jdbc.Driver");
14 p.setUsername("root");
15 p.setPassword("password");
16 p.setJmxEnabled(true);
17 p.setTestWhileIdle(false);
18 p.setTestOnBorrow(true);
19 p.setValidationQuery("SELECT 1");
20 p.setTestOnReturn(false);
21 p.setValidationInterval(30000);
22 p.setTimeBetweenEvictionRunsMillis(30000);
23 p.setMaxActive(100);
24 p.setInitialSize(10);
25 p.setMaxWait(10000);
26 p.setRemoveAbandonedTimeout(60);
27 p.setMinEvictableIdleTimeMillis(30000);
28 p.setMinIdle(10);
29 p.setLogAbandoned(true);
30 p.setRemoveAbandoned(true);
31 p.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"+
32 "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
33 DataSource datasource = new DataSource();
34 datasource.setPoolProperties(p);
35
36 Connection con = null;
37 try {
38 con = datasource.getConnection();
39 Statement st = con.createStatement();
40 ResultSet rs = st.executeQuery("select * from user");
41 int cnt = 1;
42 while (rs.next()) {
43 System.out.println((cnt++)+". Host:" +rs.getString("Host")+
44 " User:"+rs.getString("User")+" Password:"+rs.getString("Password"));
45 }
46 rs.close();
47 st.close();
48 } finally {
49 if (con!=null) try {con.close();}catch (Exception ignore) {}
50 }
51 }
52
53 }
作为数据源在Tomcat中使用
1 <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设置为true
2.必须将数据源转换为org.apache.tomcat.jdbc.pool.DataSource
01 Connection con = null;
02 try {
03 Future future = datasource.getConnectionAsync();
04 while (!future.isDone()) {
05 System.out.println("Connection is not yet available. Do some background work");
06 try {
07 Thread.sleep(100); //simulate work
08 }catch (InterruptedException x) {
09 Thread.currentThread().interrupted();
10 }
11 }
12 con = future.get(); //should return instantly
13 Statement st = con.createStatement();
14 ResultSet rs = st.executeQuery("select * from user");
链接1:http://www.oschina.net/question/12_36910target=_blank?sort=time&p=2
链接2 Tomcat JDBC pool源码部析:http://guojuanjun.blog.51cto.com/277646/1172327/
链接3:http://blog.csdn.net/dliyuedong/article/details/23332567
链接3-1:http://blog.csdn.net/zhushanzhi/article/details/56484812
3---3-1 可以知道是在tomcat 中的service.xml 或在项目中webinfo/下 content.xml(将会覆盖tomcat的conentx.xml)
链接4:http://blog.sina.com.cn/s/blog_454fbf7401012m0h.html
Tomcat 自带的 JDBC 连接池官方文档中文版
英文使用手册:https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html