【JDBC连接池】Tomcat连接池v8.5.9官方文档翻译
来源:互联网 发布:南昌高能金域名都 编辑:程序博客网 时间:2024/06/15 20:18
说明:
1. 英文文档原文地址:http://tomcat.apache.org/tomcat-8.5-doc/jdbc-pool.html
2. 译者:陈佳志chenjazz
3. 参考了另一篇翻译文档:http://wiki.jikexueyuan.com/project/tomcat/tomcat-jdbc-pool.html
4. 【】中的文字原文中不存在,属于译者解释性的
===================以下为正文===================
一、简介
JDBC 连接池 org.apache.tomcat.jdbc.pool 是 Apache Commons DBCP 连接池的一种替换或备选方案。
那为什么需要一个新的连接池?
原因如下:
1. Commons DBCP 1.x 是单线程。为了线程安全,在对象分配或对象返回的短期时间内,DBCP 锁定了整个连接池。但注意这并不适用于 Commons DBCP 2.x。【对象指的是Connection对象】
2. Commons DBCP 1.x 可能会变得很慢。当逻辑 CPU 数目增长,或者试图借出或归还对象的并发线程增加时,性能就会受到影响。高并发系统受到的影响会更为显著。注意这并不适用于 Commons DBCP 2.x。
3. Commons DBCP 拥有 60 多个类。tomcat-jdbc-pool 核心只有 8 个类。因此如果未来需求变更着想,仅需要更少的改动。我们真正需要的只是连接池本身,其余的只是附属。
4. Commons DBCP 使用静态接口,因此对于指定版本的 JRE,只能采用正确版本的 DBCP,否则就会出现 NoSuchMethodException 异常。
5. 当DBCP 可以用其他更简便的实现来替代时,实在不值得重写那 60 个类。
6. Tomcat JDBC 连接池无需为库本身添加额外线程,就能获取异步获取连接。
7. Tomcat JDBC 连接池是 Tomcat 的一个模块,仅依赖Tomcat JULI 这个Tomcat中的简化日志架构。
8. 可以使用 javax.sql.PooledConnection 接口获取底层连接。
9. 防止饥饿。如果池变空,线程将等待一个连接。当连接返回时,池就将唤醒正确的等待线程。大多数连接池只会一直维持饥饿状态。【?】
Tomcat JDBC 连接池还具有一些其他连接池实现所没有的特点:
- 支持高并发环境与多核/CPU 系统。
- 接口的动态实现。在你的运行环境下支持 java.sql 与 java.sql 接口(就像 JDBC 驱动一样),甚至在利用低版本的 JDK 来编译时。
- 验证间隔时间。我们不必每次使用单个连接时都进行验证,可以在借出(borrow )或归还(return )连接时进行验证,只要不低于我们所设定的间隔时间就行。
- 只执行一次查询。当与数据库建立起连接时,只执行一次的可配置查询。这项功能对会话设置非常有用,因为你可能会想在连接建立的整个时段内都保持会话。
- 能够配置自定义拦截器。通过自定义拦截器来增强功能。可以使用拦截器来采集查询统计,缓存会话状态,重新连接之前失败的连接,重新查询,缓存查询结果,等等。可以使用大量的选项并且自定义拦截器也是没有限制的没有绑定到特定版本JDK的 java.sql/javax.sql 接口。
- 高性能。后文将举例展示一些性能差异。
- 极其简单。它的实现非常简单,代码行数与源文件都非常少,这都有赖于从一开始研发它时,就把简洁当做重中之重。对比一下 c3p0 ,它的源文件超过了 200 个(最近一次统计),而 Tomcat JDBC 核心只有 8 个文件,连接池本身则大约只有这个数目的一半,所以能够轻易地跟踪和修改可能出现的 Bug。
- 异步连接获取。可将连接请求队列化,系统返回
Future<Connection>
。 - 更好地处理空闲连接。不再直接把空闲连接关闭,通过更为巧妙的算法控制空闲连接池的规模。
- 可以控制连接应被废弃的时间:当池满了即废弃,或者指定一个池使用容差值,发生超时就进行废弃处理。
- 通过查询或语句来重置废弃连接计时器。允许一个使用了很长时间的连接不因为超时而被废弃。这一点是通过使用 ResetAbandonedTimer 来实现的。
- 经过指定时间后,关闭连接。与返回池的时间相类似。
- 当连接要被释放时,获取 JMX 通知并记录所有日志。它类似于 removeAbandonedTimeout,但却不需要采取任何行为,只报告信息。通过 suspectTimeout 属性来实现。
- 可以通过 java.sql.Driver、javax.sql.DataSource 或 javax.sql.XADataSource 获取连接。通过 dataSource 与 dataSourceJNDI 属性实现这一点。
- 支持 XA 连接。 16.
二、如何使用
对于熟悉 Commons DBCP 的人来说,转而使用 Tomcat 连接池是非常简单的事。从其他连接池转换过来也非常容易。
附加功能
除了其他多数连接池能够提供的功能外,Tomcat 连接池还提供了一些附加功能:
- initSQL
当连接创建后,能够执行一个只执行一次的SQL 语句。
- validationInterval
恰当地在连接上运行验证,同时又能避免太多频繁地执行验证。
- jdbcInterceptors
灵活并且可插拔的拦截器,能够对池进行各种自定义,执行各种查询,处理结果集。下文将予以详述。
- fairQueue
将 fair 标志设为 true,以达成线程公平性,或使用异步连接获取。
在Apache Tomcat 容器内部(使用)
Tomcat JDBC 文档描述中:(在Tomcat 容器内部,)Tomcat 连接池被配置为一个资源。唯一的区别在于,你必须指定 factory 属性,并将其值设为
org.apache.tomcat.jdbc.pool.DataSourceFactory。
独立(使用)
连接池只有一个依赖文件,tomcat-juli.jar。要想在使用 bean 实例化的单一项目中使用池,实例化的 Bean 为org.apache.tomcat.jdbc.pool.DataSource。下文讲到将连接池配置为 JNDI 资源时会涉及到同一属性,也是用来将数据源配置成 bean 的。
JMX
连接池对象暴露了一个可以被注册的 MBean。为了让连接池对象创建 MBean,jmxEnabled 标志必须设为 true。这并不是说连接池会注册到 MBean 服务器。在像 Tomcat 这样的容器中,Tomcat 本身注册就在 MBean 服务器上注册了 DataSource。org.apache.tomcat.jdbc.pool.DataSource 对象会注册实际的连接池 MBean。如果你在容器外运行,可以将 DataSource 注册在任何你指定的对象名下,然后将这种注册传播到底层池。要想这样做,你必须调用 mBeanServer.registerMBean(dataSource.getPool().getJmxPool(),objectname)。在调用之前,一定要保证通过调用 dataSource.createPool() 创建了池。
三、属性
为了能够顺畅地在 Commons DBCP 与 Tomcat JDBC 连接池 之间转换,大多数属性名称及其含义都是相同的。
JNDI 工厂与类型
系统属性
系统属性作用于 JVM 范围,影响创建于 JVM 内的所有池。
常用属性
增强属性
四、高级用法
JDBC 拦截器
要想看看拦截器使用方法的具体实例,可以看看 org.apache.tomcat.jdbc.pool.interceptor.ConnectionState源码。这个简单的拦截器缓存了三个属性:autoCommit、readOnly、transactionIsolation,为的是避免系统与数据库之间无用的往返。
当需求增加时,连接池核心将会增加更多的拦截器。欢迎贡献你的才智!
拦截器当然并不局限于 java.sql.Connection,当然也可以对方法调用的任何结果进行包装。你可以构建查询性能分析器,以便当查询运行时间超过预期时间时提供 JMX 通知。
配置 JDBC 拦截器
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)"
系统会自动忽略属性名称、属性值以及类名前后多余的空格字符。
org.apache.tomcat.jdbc.pool.JdbcInterceptor
这个类用来是所有拦截器的抽象基类,它无法被实例化。
org.apache.tomcat.jdbc.pool.interceptor.ConnectionState
这个类能为下列属性缓存连接:autoCommit、readOnly、transactionIsolation 及 catalog。这是一种性能增强功能,当利用已设定的值来调用 getter 与 setter 时,它能够避免往返数据库。
org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer
这个类用来跟踪所有使用 createStatement、prepareStatement 或 prepareCall 的语句,当连接返回池后,关闭这些语句。
org.apache.tomcat.jdbc.pool.interceptor.StatementCache
缓存连接中的 PreparedStatement 或 CallableStatement 实例。
它会针对每个连接对这些语句进行缓存,然后计算池中所有连接的整体缓存数,如果缓存数超过了限制 max,就不再对随后的语句进行缓存,而是直接关闭它们。
org.apache.tomcat.jdbc.pool.interceptor.StatementDecoratorInterceptor
请参看 48392【bug : https://bz.apache.org/bugzilla/show_bug.cgi?id=48392】。拦截器会包装语句和结果集,从而防止对使用了 ResultSet.getStatement().getConnection() 和 Statement.getConnection() 方法的实际连接进行访问。
org.apache.tomcat.jdbc.pool.interceptor.QueryTimeoutInterceptor
当新语句创建时,自动调用 java.sql.Statement.setQueryTimeout(seconds)。池本身并不会让查询超时,完全是依靠 JDBC 驱动来强制查询超时。
org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport
当查询超过失败容差值时,记录查询性能并发布日志项目。使用的日志级别为 WARN。
org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx
这是对 SlowQueryReport 的扩展,除了发布日志项目外,它还发布 JMX 通知,以便监视工具作出相关反应。该类从其父类继承了所有属性。它使用了 Tomcat 的 JMX 引擎,所以在 Tomcat 容器外部是无效的。使用该类时,默认情况下,是通过 ConnectionPool MBean 来发送 JMX 通知。如果 notifyPool=false,则 SlowQueryReportJmx 也可以注册一个 MBean。
org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer
当连接签出池中后,废弃计时器即开始计时。这意味着如果超时为 30 秒,而你使用连接运行了 10 个 10秒的查询,那么它就会被标为废弃,并可能依靠 abandonWhenPercentageFull 属性重新声明。每次成功地在连接上执行操作或执行查询时,该拦截器就会重设签出计时器。
五、代码示例
其他 JDBC 用途的 Tomcat 配置范例可以参考 相关的 Tomcat 文档。
简单的 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) {} } }}
作为资源
下例展示了如何为 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 连接池支持异步连接获取,无需为池库添加任何额外线程。这是通过在数据源上添加一个方法 Future< Connection> getConnectionAsync() 来实现的。为了使用异步获取,必须满足两个条件:
1. 必须把 failQueue 属性设为 true。
2. 必须把数据源转换为 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");
拦截器
对于启用、禁止或修改特定连接或其组件的功能而言,使用拦截器无疑是一种非常强大的方式。默认情况下,基于性能方面的考虑,连接池是无状态的。连接池本身所插入的状态是 defaultAutoCommit、defaultReadOnly、defaultTransactionIsolation,或 defaultCatalog(如果设置了这些状态)。这 4 个状态只有在连接创建时才设置。无论这些属性是否在连接使用期间被修改,池本身都不能重置它们。
拦截器必须扩展自 org.apache.tomcat.jdbc.pool.JdbcInterceptor 类。该类相当简单,你必须利用一个无参数构造函数。
public JdbcInterceptor() { }
当从连接池借出一个连接时,拦截器能够通过实现以下方法,初始化这一事件或以一些其他形式来响应该事件。
public abstract void reset(ConnectionPool parent, PooledConnection con);
上面这个方法有两个参数,一个是连接池本身的引用 ConnectionPool parent,一个是底层连接的引用 PooledConnection con。
当调用 java.sql.Connection 对象上的方法时,会导致以下方法被调用:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Method method 是被调用的实际方法,Object[] args 是参数。通过观察下面这个非常简单的例子,我们可以解释如果当连接已经关闭时,如何让 java.sql.Connection.close() 的调用变得无用。
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 之外的类,不要忘记调用超类。
配置拦截器
拦截器可以通过 jdbcInterceptors 属性或 setJdbcInterceptors 方法来配置。拦截器也可以有属性,可以通过如下方式来配置:
String jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState(useEquals=true,fast=yes)"
拦截器属性
既然拦截器也有属性,那么你也可以读取其中的属性值。你可以重写 setProperties 方法。
public void setProperties(Map
六、构建
下面利用 1.6 来构建 JDBC 连接池代码,但它也可以向后兼容到 1.5 运行时环境。为了单元测试,使用 1.6 或更高版本。
更多的关于 JDBC 用途的 Tomcat 配置范例可参看 Tomcat 文档。
从源代码构建
构建非常简单。池依赖于 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
构建文件位于 Tomcat 的源代码仓库中。
为了方便起见,在通过简单构建命令生成所需文件的地方也包含了一个构建文件。
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)
系统针对 Maven 构建进行组织,但是没有生成发布组件,只有库本身。
- 【JDBC连接池】Tomcat连接池v8.5.9官方文档翻译
- Tomcat 自带的 JDBC 连接池官方文档中文版
- Tomcat 自带的 JDBC 连接池官方文档中文版
- tomcat jdbc 连接池
- JDBC以及Tomcat连接池
- JDBC以及Tomcat连接池
- tomcat+jdbc+sqlserver2008连接池
- Tomcat的JDBC连接池
- Tomcat 的 JDBC 连接池
- Tomcat 7连接池--Tomcat jdbc pool
- 建立基于 JDBC 的 Tomcat 连接池
- 建立基于 JDBC 的 Tomcat 连接池
- 建立基于 JDBC 的 Tomcat 连接池
- tomcat jdbc 连接池 参数说明
- tomcat jdbc pool 连接池配置
- 在tomcat下配置jdbc连接池
- spring boot(10)-tomcat jdbc连接池
- spring boot(10)-tomcat jdbc连接池
- 音视频相关知识记录
- HDU 1026 Ignatius and the Princess I(BFS)
- LeetCode -- Wiggle Sort II
- C语言学习2017-1-5
- Spring AOP实现原理2
- 【JDBC连接池】Tomcat连接池v8.5.9官方文档翻译
- Charles Petzold《Code》----2017.1.5 读9章
- android-基础知识解析
- LeetCode -- Rotate Function
- 《Ansible_Up-And-Running》笔记1-Ansible超详细使用指南
- mongodb数据类型对比
- MASM32编程实现运行时自动提示要求以管理员帐户来运行
- ReactJS组件的生命周期详解
- java垃圾收集描述