- 简介
- 如何使用
- 属性
- 高级用法
- JDBC 拦截器
- 配置 JDBC 拦截器
- org.apache.tomcat.jdbc.pool.JdbcInterceptor
- org.apache.tomcat.jdbc.pool.interceptor.ConnectionState
- org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer
- org.apache.tomcat.jdbc.pool.interceptor.StatementCache
- org.apache.tomcat.jdbc.pool.interceptor.StatementDecoratorInterceptor
- org.apache.tomcat.jdbc.pool.interceptor.QueryTimeoutInterceptor
- org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport
- org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx
- org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer
- 代码示例
- 构建
Tomcat JDBC 连接池
目录
简介
JDBC 连接池 org.apache.tomcat.jdbc.pool
是 Apache Commons DBCP 连接池的替代方案。
那么为什么我们需要一个新的连接池呢?
以下是一些原因
- Commons DBCP 1.x 是单线程的。为了实现线程安全,Commons 在对象分配和对象返回期间都会短时间锁定整个连接池。请注意,这不适用于 Commons DBCP 2.x。
- Commons DBCP 1.x 可能会很慢。随着逻辑 CPU 数量的增长以及尝试借用或返回对象的并发线程数量的增加,性能会下降。对于高并发系统,影响可能很大。请注意,这不适用于 Commons DBCP 2.x。
- Commons DBCP 包含超过 60 个类。而 tomcat-jdbc-pool 核心只有 8 个类,因此对未来需求的修改将需要更少的更改。这只是运行连接池本身所需的全部,其余都是附加功能。
- Commons DBCP 使用静态接口。这意味着您必须为给定的 JRE 版本使用正确的版本,否则可能会看到
NoSuchMethodException
异常。 - 当一个连接池可以通过更简单的实现来完成时,重写 60 多个类是不值得的。
- Tomcat JDBC 连接池实现了异步检索连接的能力,而无需向库本身添加额外的线程。
- Tomcat JDBC 连接池是一个 Tomcat 模块,它依赖于 Tomcat JULI,一个用于 Tomcat 的简化日志框架。
- 使用
javax.sql.PooledConnection
接口检索底层连接。 - 无饥饿。如果连接池为空,并且线程正在等待连接,当连接返回时,连接池将唤醒正确的等待线程。大多数连接池会简单地导致饥饿。
相较于其他连接池实现的额外功能
- 支持高并发环境和多核/多 CPU 系统。
- 接口的动态实现,将支持您运行时环境的
java.sql
和javax.sql
接口(只要您的 JDBC 驱动程序也这样做),即使使用较低版本的 JDK 编译。 - 验证间隔 - 我们不必在每次使用连接时都进行验证,我们可以在借用或归还连接时进行此操作,但频率不超过我们可配置的间隔。
- 一次性查询,一个可配置的查询,在数据库连接建立时只运行一次。对于设置您希望在连接建立的整个过程中存在的会话设置非常有用。
- 配置自定义拦截器的能力。这允许您编写自定义拦截器来增强功能。您可以使用拦截器收集查询统计信息、缓存会话状态、在失败时重新连接、重试查询、缓存查询结果等等。您的选择是无限的,并且拦截器是动态的,不绑定到
java.sql
/javax.sql
接口的 JDK 版本。 - 高性能 - 我们稍后将展示一些性能差异
- 极其简单,由于其非常简化的实现,代码行数和源文件数量都非常少,与 c3p0 拥有超过 200 个源文件(我们上次检查时)相比,Tomcat JDBC 的核心只有 8 个文件,连接池本身大约是其一半。如果发生错误,它们将更容易追踪和修复。从一开始,减少复杂性就是重点。
- 异步连接检索 - 您可以排队请求连接并接收一个
Future<Connection>
返回。 - 更好的空闲连接处理。它不是直接关闭连接,而是仍然可以将连接放入池中,并使用更智能的算法调整空闲连接池的大小。
- 您可以决定何时将连接视为已废弃,是在连接池满时,还是通过指定连接池使用阈值在超时时直接废弃。
- 废弃连接计时器会在语句/查询活动时重置。这允许长时间使用的连接不会超时。这是通过使用
ResetAbandonedTimer
实现的。 - 在连接建立一定时间后关闭连接。根据连接寿命在返回连接池时关闭。
- 当连接被怀疑已废弃时,获取 JMX 通知和日志条目。这类似于
removeAbandonedTimeout
,但它不采取任何行动,只报告信息。这是通过使用suspectTimeout
属性实现的。 - 连接可以从
java.sql.Driver
、javax.sql.DataSource
或javax.sql.XADataSource
中检索。这是通过使用dataSource
和dataSourceJNDI
属性实现的。 - XA 连接支持
如何使用
Tomcat 连接池的使用已经尽可能简化,对于熟悉 commons-dbcp 的用户来说,迁移将非常简单。从其他连接池迁移也相当直接。
附加特性
Tomcat 连接池提供了一些比大多数其他连接池更多的额外功能
initSQL
- 在连接创建时只运行一次 SQL 语句的能力validationInterval
- 除了对连接进行验证外,避免过于频繁地运行验证。jdbcInterceptors
- 灵活且可插拔的拦截器,用于创建连接池、查询执行和结果集处理方面的任何自定义。更多信息请参阅高级部分。fairQueue
- 将公平标志设置为 true 以实现线程公平性或使用异步连接检索
在 Apache Tomcat 容器内部
Tomcat 连接池被配置为一个资源,详见 Tomcat JDBC 文档。唯一的区别是您必须指定 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 服务器,而仅仅是 MBean 已被创建。在像 Tomcat 这样的容器中,Tomcat 本身会将 DataSource 注册到 MBean 服务器,然后 org.apache.tomcat.jdbc.pool.DataSource
对象将注册实际的连接池 MBean。如果您在容器外部运行,您可以将 DataSource 注册到您指定的任何对象名称下,它会将注册传播到底层连接池。要做到这一点,您需要调用 mBeanServer.registerMBean(dataSource.getPool().getJmxPool(),objectname)
。在此调用之前,请确保已通过调用 dataSource.createPool()
创建了连接池。
属性
为了提供从 commons-dbcp 到 tomcat-jdbc-pool 的非常简单的切换,大多数属性都是相同的,并且具有相同的含义。
JNDI 工厂和类型
属性 | 描述 |
---|---|
factory |
factory 是必需的,其值应为 |
type |
类型应始终为 根据类型,将创建 |
系统属性
系统属性是 JVM 全局的,影响在 JVM 中创建的所有连接池。
属性 | 描述 |
---|---|
org.apache.tomcat.jdbc.pool.onlyAttemptCurrentClassLoader |
(boolean) 控制动态类(如 JDBC 驱动程序、拦截器和验证器)的类加载。如果设置为 |
通用属性
这些属性在 commons-dbcp 和 tomcat-jdbc-pool 之间共享,在某些情况下默认值可能不同。
属性 | 描述 |
---|---|
defaultAutoCommit |
(boolean) 此连接池创建的连接的默认自动提交状态。如果未设置,则默认为 JDBC 驱动程序默认值(如果未设置,则不会调用 |
defaultReadOnly |
(boolean) 此连接池创建的连接的默认只读状态。如果未设置,则不会调用 |
defaultTransactionIsolation |
(String) 此连接池创建的连接的默认事务隔离状态。以下之一:(参见 javadoc)
如果未设置,则不会调用该方法,并默认为 JDBC 驱动程序。 |
defaultCatalog |
(String) 此连接池创建的连接的默认目录。 |
driverClassName |
(String) 要使用的 JDBC 驱动程序的完全限定 Java 类名。该驱动程序必须与 tomcat-jdbc.jar 位于相同的类加载器中。 |
username |
(String) 传递给 JDBC 驱动程序以建立连接的用户名。请注意, |
password |
(String) 传递给 JDBC 驱动程序以建立连接的密码。请注意, |
maxActive |
(int) 此连接池中可同时分配的最大活动连接数。默认值为 |
maxIdle |
(int) 连接池中应始终保持的最大连接数。默认值为 |
minIdle |
(int) 连接池中应始终保持的最小已建立连接数。如果验证查询失败,连接池可能会缩小到低于此数量。默认值源自 |
initialSize |
(int) 连接池启动时创建的初始连接数。默认值为 |
maxWait |
(int) 当没有可用连接时,连接池在抛出异常之前等待连接返回的最大毫秒数。默认值为 |
testOnBorrow |
(boolean) 指示对象在从连接池借用之前是否会被验证。如果对象未能通过验证,它将从连接池中移除,我们将尝试借用另一个。为了获得更高效的验证,请参阅 |
testOnConnect |
(boolean) 指示对象在连接首次创建时是否会被验证。如果对象未能通过验证,将抛出 |
testOnReturn |
(boolean) 指示对象在返回连接池之前是否会被验证。默认值为 |
testWhileIdle |
(boolean) 指示对象是否将由空闲对象驱逐器(如果有)进行验证。如果对象未能通过验证,它将从连接池中移除。默认值为 |
validationQuery |
(String) 用于在将连接返回给调用者之前验证此连接池中连接的 SQL 查询。如果指定,此查询不必返回任何数据,它只不能抛出 |
validationQueryTimeout |
(int) 连接验证查询失败前的超时时间(秒)。这是通过在执行 |
validatorClassName |
(String) 实现 |
timeBetweenEvictionRunsMillis |
(int) 空闲连接验证/清理线程两次运行之间休眠的毫秒数。此值不应低于 1 秒。它决定了我们检查空闲、废弃连接的频率,以及我们验证空闲连接的频率。如果 |
numTestsPerEvictionRun |
(int) 在 tomcat-jdbc-pool 中未使用的属性。 |
minEvictableIdleTimeMillis |
(int) 对象在池中空闲多久才符合被驱逐的最低时间量。默认值为 |
accessToUnderlyingConnectionAllowed |
(boolean) 未使用的属性。可以通过在池化连接上调用 |
removeAbandoned |
(boolean) 标志,用于在废弃连接超过 |
removeAbandonedTimeout |
(int) 废弃(使用中)连接在被移除之前的超时时间(秒)。默认值为 |
logAbandoned |
(boolean) 标志,用于记录废弃连接的应用程序代码的堆栈跟踪。记录废弃连接会增加每次借用连接的开销,因为必须生成堆栈跟踪。默认值为 |
connectionProperties |
(String) 建立新连接时将发送到 JDBC 驱动程序的连接属性。字符串格式必须为 [propertyName=property;]* 注意 - "user" 和 "password" 属性将显式传递,因此无需包含在此处。默认值为 |
poolPreparedStatements |
(boolean) 未使用的属性。 |
maxOpenPreparedStatements |
(int) 未使用的属性。 |
Tomcat JDBC 增强属性
属性 | 描述 |
---|---|
initSQL |
(String) 连接首次创建时要运行的自定义查询。默认值为 |
jdbcInterceptors |
(String) 一个以分号分隔的类名列表,这些类名扩展了 这些拦截器将作为拦截器插入到 预定义拦截器 更多预定义拦截器在JDBC 拦截器部分中有详细描述。 |
validationInterval |
(long) 避免过度验证,最多以这个频率(毫秒)运行验证。如果连接需要验证,但在此间隔内已进行过验证,则不会再次验证。默认值为 |
jmxEnabled |
(boolean) 是否向 JMX 注册连接池。默认值为 |
fairQueue |
(boolean) 如果您希望对 getConnection 的调用以真正的 FIFO 方式公平处理,请设置为 true。这将使用 |
abandonWhenPercentageFull |
(int) 已废弃(超时)的连接不会被关闭和报告,除非正在使用的连接数高于 |
maxAge |
(long) 在重新创建连接之前保持连接的毫秒数。当从连接池借用连接时,连接池将检查是否已达到 |
useEquals |
(boolean) 如果您希望 |
suspectTimeout |
(int) 超时值(秒)。默认值为 |
rollbackOnReturn |
(boolean) 如果 |
commitOnReturn |
(boolean) 如果 |
alternateUsernameAllowed |
(boolean) 默认情况下,出于性能原因,jdbc-pool 将忽略 然而,连接池可以配置为允许每次请求连接时使用不同的凭据。要启用 |
dataSource |
(javax.sql.DataSource) 将数据源注入连接池,连接池将使用该数据源检索连接,而不是使用 |
dataSourceJNDI |
(String) 数据源在 JNDI 中查找并用于建立数据库连接的 JNDI 名称。请参阅 |
useDisposableConnectionFacade |
(boolean) 如果您希望在连接上设置一个门面,使其在关闭后不能被重用,请将其设置为 true。这可以防止线程持有已关闭连接的引用,并对其执行查询。默认值为 |
logValidationErrors |
(boolean) 将此设置为 true 可将验证阶段的错误记录到日志文件中。如果设置为 true,错误将以 SEVERE 级别记录。为了向后兼容,默认值为 |
propagateInterruptState |
(boolean) 将此设置为 true 可传播已中断线程的中断状态(不清除中断状态)。为了向后兼容,默认值为 |
ignoreExceptionOnPreLoad |
(boolean) 在初始化连接池时是否忽略连接创建错误的标志。如果您想在初始化连接池时忽略连接创建错误,请设置为 true。如果您想通过抛出异常来使连接池初始化失败,请设置为 false。默认值为 |
useStatementFacade |
(boolean) 如果您希望包装语句以使 |
高级用法
JDBC 拦截器
要查看如何使用拦截器的示例,请查看 org.apache.tomcat.jdbc.pool.interceptor.ConnectionState
。这个简单的拦截器是一个包含事务隔离级别、自动提交和只读状态这三个属性的缓存,以便系统避免不必要的数据库往返。
未来将根据需要向连接池核心添加更多拦截器。欢迎贡献!
拦截器当然不仅限于 java.sql.Connection
,还可以用于包装方法调用的任何结果。您可以构建查询性能分析器,在查询运行时间超过预期时提供 JMX 通知。
配置 JDBC 拦截器
JDBC 拦截器的配置通过 jdbcInterceptors 属性完成。该属性包含一个以分号分隔的类名列表。如果类名不是完全限定的,它将以 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
所有拦截器的抽象基类,不能被实例化。
属性 | 描述 |
---|---|
useEquals |
(boolean) 如果您希望 |
org.apache.tomcat.jdbc.pool.interceptor.ConnectionState
缓存连接的以下属性:autoCommit
、readOnly
、transactionIsolation
和 catalog
。这是一种性能增强,旨在避免在调用 getter 或使用已设置的值调用 setter 时与数据库进行往返。
属性 | 描述 |
---|
org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer
跟踪所有使用 createStatement
、prepareStatement
或 prepareCall
创建的语句,并在连接返回连接池时关闭这些语句。
属性 | 描述 |
---|---|
trace |
(boolean as String) 启用未关闭语句的跟踪。当启用且连接关闭但语句未关闭时,拦截器将记录所有堆栈跟踪。默认值为 |
org.apache.tomcat.jdbc.pool.interceptor.StatementCache
缓存连接上的 PreparedStatement
和/或 CallableStatement
实例。
语句按连接缓存。计数限制是针对属于同一连接池的所有连接全局计数的。一旦计数达到 max
,后续语句将不会返回到缓存中,而是立即关闭。
属性 | 描述 |
---|---|
prepared |
(boolean as String) 启用对使用 |
callable |
(boolean as String) 启用对使用 |
max |
(int as String) 连接池中缓存语句数量的限制。默认值为 |
org.apache.tomcat.jdbc.pool.interceptor.StatementDecoratorInterceptor
参见 48392。用于包装语句和结果集的拦截器,以防止使用 ResultSet.getStatement().getConnection()
和 Statement.getConnection()
方法访问实际连接。
属性 | 描述 |
---|
org.apache.tomcat.jdbc.pool.interceptor.QueryTimeoutInterceptor
当创建新语句时,自动调用 java.sql.Statement.setQueryTimeout(seconds)
。连接池本身不会使查询超时,它仍然取决于 JDBC 驱动程序来强制执行查询超时。
属性 | 描述 |
---|---|
queryTimeout |
(int as String) 查询超时设置的秒数。小于或等于零的值将禁用此功能。默认值为 |
org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport
跟踪查询性能,并在查询超过时间阈值或失败时发出日志条目。使用的日志级别是 WARN
。
属性 | 描述 |
---|---|
threshold |
(int as String) 查询在发出日志警报之前必须超过的毫秒数。默认值为 |
maxQueries |
(int as String) 为节省内存空间而跟踪的最大查询数量。小于或等于 0 的值将禁用此功能。默认值为 |
logSlow |
(boolean as String) 如果您希望记录慢查询,请设置为 |
logFailed |
(boolean as String) 如果您希望记录失败的查询,请设置为 |
org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx
扩展 SlowQueryReport
,除了日志条目外,它还发出 JMX 通知供监控工具响应。继承其父类的所有属性。此类使用 Tomcat 的 JMX 引擎,因此它在 Tomcat 容器外部无法工作。默认情况下,如果启用,JMX 通知通过 ConnectionPool mbean 发送。如果 notifyPool=false
,SlowQueryReportJmx
也可以注册 MBean。
属性 | 描述 |
---|---|
notifyPool |
(boolean as String) 如果您希望 JMX 通知发送到 |
objectName |
(String) 定义一个有效的 |
org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer
废弃计时器在连接从连接池中取出时启动。这意味着,如果您有一个 30 秒的超时时间,并且使用该连接运行 10 个 10 秒的查询,则该连接将被标记为废弃,并可能根据 abandonWhenPercentageFull
属性被回收。使用此拦截器,您每次对连接执行操作或成功执行查询时,都会重置取出计时器。
属性 | 描述 |
---|
代码示例
Tomcat 配置 JDBC 用法的其他示例可以在 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()
的方法来实现。为了使用异步检索,必须满足两个条件:
- 您必须将
fairQueue
属性配置为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");
拦截器
拦截器是一种强大的方式,可以启用、禁用或修改特定连接或其子组件上的功能。拦截器有许多不同的用例。默认情况下,出于性能原因,连接池是无状态的。连接池本身插入的唯一状态是 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);
这里有一个观察。它是方法名的比较。一种方法是使用 "close".equals(method.getName())
。上面我们看到方法名和 static final String
引用之间的直接引用比较。根据 JVM 规范,方法名和静态最终字符串最终位于共享常量池中,因此引用比较应该有效。当然,也可以这样做:
if (compare(CLOSE_VAL,method)) {
if (isClosed()) return null; //noop for already closed.
}
return super.invoke(proxy,method,args);
compare(String,Method)
将使用拦截器上的 useEquals
标志,并在设置 useEquals=true
标志时进行引用比较或字符串值比较。
连接池启动/停止
当连接池启动或关闭时,您可以收到通知。您每个拦截器类只会收到一次通知,即使它是一个实例方法。您将使用当前未附加到连接池的拦截器收到通知。
public void poolStarted(ConnectionPool pool) {
}
public void poolClosed(ConnectionPool pool) {
}
覆盖这些方法时,如果您扩展的类不是 JdbcInterceptor
,请不要忘记调用 super。
配置拦截器
拦截器通过 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()));
}
}
获取实际的 JDBC 连接
连接池围绕实际连接创建包装器,以便正确地对其进行池化。我们还在这些包装器中创建拦截器,以便能够执行某些功能。如果需要检索实际连接,可以使用 javax.sql.PooledConnection
接口来实现。
Connection con = datasource.getConnection();
Connection actual = ((javax.sql.PooledConnection)con).getConnection();
构建
我们使用 1.6 构建 JDBC 连接池代码,但它在运行时环境上向后兼容到 1.5。对于单元测试,我们使用 1.6 及更高版本。
Tomcat 配置 JDBC 用法的其他示例可以在 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 构建而设计的,但确实会生成发布工件。仅仅是库本身。