Tomcat的JDBC连接池org.apache.tomcat.jdbc.pool
是一个替换或到一个替代Apache的百科全书DBCP 连接池。
那么,为什么我们需要一个新的连接池?
原因如下:
NoSuchMethodException
异常。javax.sql.PooledConnection
接口检索基础连接 。在其他连接池实现上添加的功能
java.sql
和javax.sql
接口(只要JDBC驱动程序也是如此)。java.sql
/ javax.sql
接口的JDK版本 。Future
退款。ResetAbandonedTimer
removeAbandonedTimeout
但不执行任何操作,仅报告信息。这是使用suspectTimeout
属性来实现的。java.sql.Driver
, 这可以使用和属性来实现。javax.sql.DataSource
javax.sql.XADataSource
dataSource
dataSourceJNDI
Tomcat连接池的使用已尽可能地简单,对于熟悉commons-dbcp的人来说,过渡将非常简单。从其他连接池迁移也很简单。
附加功能
Tomcat连接池提供了大多数其他池所不具备的一些其他功能:
initSQL
-创建连接后,仅运行一次SQL语句的能力validationInterval
-除了对连接运行验证之外,请避免过于频繁地运行它们。jdbcInterceptors
-灵活且可插入的拦截器,可围绕池,查询执行和结果集处理创建任何自定义项。有关更多信息,请参见高级部分。fairQueue
-将fair标志设置为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本身会向MBean服务器注册数据源,org.apache.tomcat.jdbc.pool.DataSource
然后该 对象将注册实际的连接池MBean。如果您在容器外部运行,则可以使用您指定的任何对象名称自行注册DataSource,并将其传播到基础池。为此,您将致电mBeanServer.registerMBean(dataSource.getPool().getJmxPool(),objectname)
。在进行此调用之前,请通过调用确保已创建池dataSource.createPool()
。
为了提供与commons-dbcp和tomcat-jdbc-pool之间的非常简单的切换,大多数属性都是相同的,并且具有相同的含义。
JNDI工厂和类型
属性 | 描述 |
---|---|
factory |
工厂是必填项,其值应为 |
type |
类型应始终为 根据类型将创建a |
系统属性
系统属性是JVM范围的,影响在JVM中创建的所有池
属性 | 描述 |
---|---|
org.apache.tomcat.jdbc.pool.onlyAttemptCurrentClassLoader |
(布尔值)控制动态类(例如JDBC驱动程序,拦截器和验证器)的类加载。如果设置为 |
共同属性
这些属性在commons-dbcp和tomcat-jdbc-pool之间共享,在某些情况下,默认值是不同的。
属性 | 描述 |
---|---|
defaultAutoCommit |
(布尔值)此池创建的连接的默认自动提交状态。如果未设置,则默认值为JDBC驱动程序默认值(如果未设置,则 |
defaultReadOnly |
(布尔值)此池创建的连接的默认只读状态。如果未设置,则 |
defaultTransactionIsolation |
(字符串)此池创建的连接的默认TransactionIsolation状态。以下之一:(请参阅javadoc)
如果未设置,则不会调用该方法,并且默认为JDBC驱动程序。 |
defaultCatalog |
(字符串)此池创建的默认连接目录。 |
driverClassName |
(字符串)要使用的JDBC驱动程序的标准Java类名称。必须从与tomcat-jdbc.jar相同的类加载器中访问驱动程序 |
username |
(字符串)要传递给我们的JDBC驱动程序以建立连接的连接用户名。请注意, |
password |
(字符串)要传递给我们的JDBC驱动程序以建立连接的连接密码。请注意, |
maxActive |
(int)可以同时从该池分配的最大活动连接数。默认值为 |
maxIdle |
(int)始终应保留在池中的最大连接数。默认值为 |
minIdle |
(int)始终应保留在池中的已建立连接的最小数目。如果验证查询失败,则连接池可以缩小到该数字以下。默认值源自 |
initialSize |
(int)启动池时创建的初始连接数。默认值为 |
maxWait |
(int)在引发异常之前,池将等待(无可用连接时)连接返回的最大毫秒数。默认值为 |
testOnBorrow |
(布尔值)指示从池中借用对象之前是否对其进行验证。如果对象验证失败,它将被从池中删除,我们将尝试借用另一个对象。为了进行更有效的验证,请参阅 |
testOnConnect |
(布尔值)指示在首次创建连接时是否将验证对象。如果对象验证失败,则将引发 |
testOnReturn |
(布尔值)指示在将对象返回到池之前是否将对其进行验证。默认值为 |
testWhileIdle |
(布尔值)指示空闲对象退出者(如果有)是否将验证对象。如果对象验证失败,则会将其从池中删除。默认值为, |
validationQuery |
(字符串)SQL查询,该查询将用于验证来自此池的连接,然后再将其返回给调用方。如果指定,此查询不必返回任何数据,而不能抛出 |
validationQueryTimeout |
(int)连接验证查询失败之前的超时(以秒为单位)。这可以通过调用 |
validatorClassName |
(字符串)实现 |
timeBetweenEvictionRunsMillis |
(int)空闲连接验证/清除线程的运行之间要休眠的毫秒数。此值不应在1秒内设置。它决定了我们检查空闲,被放弃的连接的频率以及验证空闲连接的频率。 |
numTestsPerEvictionRun |
(int)tomcat-jdbc-pool中未使用的属性。 |
minEvictableIdleTimeMillis |
(int)一个对象在有资格被驱逐之前可以在池中空闲的最短时间。默认值为 |
accessToUnderlyingConnectionAllowed |
(布尔值)未使用的属性。可以通过调用 |
removeAbandoned |
(布尔值)标记以删除超过的已放弃连接 |
removeAbandonedTimeout |
(int)超时(以秒为单位),可以删除已废弃(正在使用)的连接。默认值为 |
logAbandoned |
(布尔值)标记为放弃连接的应用程序代码记录堆栈跟踪。记录废弃的连接会增加每次连接借用的开销,因为必须生成堆栈跟踪。默认值为 |
connectionProperties |
(字符串)建立新连接时将发送到我们的JDBC驱动程序的连接属性。字符串的格式必须为[propertyName = property;] *注意-“ user”和“ password”属性将显式传递,因此不需要在此处包含它们。默认值为 |
poolPreparedStatements |
(布尔值)未使用的属性。 |
maxOpenPreparedStatements |
(int)不使用的属性。 |
Tomcat JDBC增强属性
属性 | 描述 |
---|---|
initSQL |
(字符串)首次创建连接时要运行的自定义查询。默认值为 |
jdbcInterceptors |
(字符串)扩展名的 这些拦截器将作为拦截器插入到 预定义的拦截器: -跟踪自动提交,只读,目录和事务隔离级别。 -跟踪打开的语句,并在连接返回到池时关闭它们。 更多预定义的拦截器在“ JDBC拦截器”部分中进行了详细描述 。 |
validationInterval |
(长)避免过多的验证,最多只能在此频率下运行验证-时间以毫秒为单位。如果连接应进行验证,但之前已在此时间间隔内进行验证,则不会再次对其进行验证。默认值为 |
jmxEnabled |
(布尔值)是否向JMX注册池。默认值为 |
fairQueue |
(布尔值)如果希望以真正的FIFO方式公平对待对getConnection的调用,则设置为true。这将 |
abandonWhenPercentageFull |
(int)除非正在使用的连接数超过定义的百分比,否则已放弃(超时)的连接不会关闭并报告 |
maxAge |
(长)以毫秒为单位的时间,以重新建立连接。当从池中借用连接时,池将检查 |
useEquals |
(布尔值)如果您希望使用 |
suspectTimeout |
(int)超时值,以秒为单位。默认值为 |
rollbackOnReturn |
(布尔值)如果 |
commitOnReturn |
(布尔值)如果是, |
alternateUsernameAllowed |
(布尔值)默认情况 但是,可以将池配置为允许每次请求连接时使用不同的凭据。要启用 |
dataSource |
(javax.sql.DataSource)将数据源注入连接池,该池将使用数据源来检索连接,而不是使用 |
dataSourceJNDI |
(字符串)要在JNDI中查找然后用于建立与数据库的连接的数据源的JNDI名称。请参阅 |
useDisposableConnectionFacade |
(布尔值)如果希望在连接上放置外观,则将其设置为true,以使其在关闭后无法重复使用。这样可以防止线程保留已调用的已关闭连接的引用,以对其执行查询。默认值为 |
logValidationErrors |
(布尔值)将此属性设置为true可以在验证阶段将错误记录到日志文件中。如果设置为true,则错误将记录为SEVERE。默认值是 |
propagateInterruptState |
(布尔值)将此值设置为true可以传播已被中断的线程的中断状态(不清除中断状态)。默认值是 |
ignoreExceptionOnPreLoad |
(布尔值)标记初始化池时是否忽略连接创建错误。如果要在初始化池时忽略连接创建错误,请设置为true。如果要通过引发异常使池初始化失败,请设置为false。默认值为 |
useStatementFacade |
(布尔值)如果希望包装语句以便启用, |
JDBC拦截器
要查看有关如何使用拦截器的示例,请查看 org.apache.tomcat.jdbc.pool.interceptor.ConnectionState
。这个简单的拦截器是三个属性的缓存,即事务隔离级别,自动提交和只读状态,以使系统避免不必要的数据库往返。
如有需要,其他拦截器将添加到池的核心。永远欢迎捐款!
拦截器当然不仅限于此,java.sql.Connection
还可以用于包装来自方法调用的任何结果。您可以构建查询性能分析器,以在查询运行时间超过预期时间时提供JMX通知。
配置JDBC拦截器
使用jdbcInterceptors属性完成JDBC拦截器的配置。该属性包含用分号分隔的类名称的列表。如果类名不完全限定,则将在该前缀之前加上 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 |
(布尔值)如果您希望使用 |
org.apache.tomcat.jdbc.pool.interceptor.ConnectionState
缓存下列属性的连接autoCommit
,readOnly
, transactionIsolation
和catalog
。这是一种性能增强,可以避免在调用getter或使用已设置的值调用setter时往返数据库。
属性 | 描述 |
---|
org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer
跟踪使用或创建的所有语句createStatement
, 并在连接返回池时关闭这些语句。 prepareStatement
prepareCall
属性 | 描述 |
---|---|
trace |
(布尔值作为字符串)启用对未关闭语句的跟踪。启用并关闭连接且未关闭语句时,拦截器将记录所有堆栈跟踪。默认值为 |
org.apache.tomcat.jdbc.pool.interceptor.StatementCache
连接上的缓存PreparedStatement
和/或CallableStatement
实例。
语句按连接缓存。对于属于同一池的所有连接,该计数限制是全局计数的。一旦达到计数max
,后续语句就不会返回到缓存,而是立即关闭。
属性 | 描述 |
---|---|
prepared |
(布尔值作为字符串)启用对 |
callable |
(布尔值作为字符串)启用对 |
max |
(以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)要为查询超时设置的秒数。小于或等于零的值将禁用此功能。默认值为 |
org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport
跟踪查询性能并在查询超过失败时间阈值时发出日志条目。使用的日志级别是WARN
属性 | 描述 |
---|---|
threshold |
(以字符串形式int表示)发出日志警报之前查询必须超过的毫秒数。默认值是 |
maxQueries |
(int作为String)为了保留内存空间而要跟踪的最大查询数。小于或等于0的值将禁用此功能。默认值为 |
logSlow |
(布尔值作为字符串)设置为 |
logFailed |
(布尔值作为字符串)设置为 |
org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx
扩展SlowQueryReport
和,除了日志条目外,它还发出JMX通知以使监视工具做出反应。从其父类继承所有属性。此类使用Tomcat的JMX引擎,因此它将无法在Tomcat容器之外工作。默认情况下,如果启用了JMX通知,则会通过ConnectionPool mbean发送该通知。该SlowQueryReportJmx
也可以注册一个MBean如果notifyPool=false
属性 | 描述 |
---|---|
notifyPool |
(布尔值为String)如果希望JMX通知转到 |
objectName |
(字符串)定义 |
org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer
从池中检出连接后,废弃的计时器将启动。这意味着,如果您有30秒的超时时间,并使用该连接运行10x10秒的查询,则会根据abandonWhenPercentageFull
属性将其标记为已放弃并可能被回收。使用此拦截器,每次您对连接执行操作或成功执行查询时,它将重置结帐计时器。
属性 | 描述 |
---|
可以在Tomcat文档中找到有关JDBC使用的Tomcat配置的其他示例。
普通的爪哇
这是有关如何创建和使用数据源的简单示例。
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查找配置资源的示例
异步连接检索
Tomcat JDBC连接池支持异步连接检索,而无需向池库中添加其他线程。通过向数据源中添加一个方法来实现此目的Future
。为了使用异步检索,必须满足两个条件:
fairQueue
属性配置为true
。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().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()
在连接已关闭的情况下对noop 进行调用
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规范,方法名称和静态最终String最终位于共享常量池中,因此引用比较应该起作用。当然也可以这样做:
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) {
}
覆盖这些方法时,如果要扩展除以下类以外的其他类,请不要忘记调用super JdbcInterceptor
配置拦截
器使用jdbcInterceptors
属性或setJdbcInterceptors
方法配置拦截器。拦截器可以具有属性,并且可以这样配置
String jdbcInterceptors=
"org.apache.tomcat.jdbc.pool.interceptor.ConnectionState(useEquals=true,fast=yes)"
拦截器属性
由于拦截器可以具有属性,因此您需要能够在拦截器中读取这些属性的值。以上面的示例为例,您可以覆盖该setProperties
方法。
public void setProperties(Map 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();
tomcat9原文