检查 JDBC 连接是否可写;使用 preferredTestQuery 或 ConnectionTester
Checking if the JDBC connection is writable; using preferredTestQuery or ConnectionTester
当前设置:
服务主机 (Java) 连接到 (JDBC) 主数据库 (MySQL) 并有一个从属(只读)以确保可靠性
场景:
如果翻转,我需要将slave升级为新的master。当前主控变为只读,新主控提升为读写。我希望使用测试查询(对数据库执行 writable 查询)自动将 C3P0 连接池刷新到新主服务器。
想法:
探索一种自动刷新JDBC连接池的方法,以便在发生翻转时连接到新的master(当前master将是RO,slave将被提升为RW,master cname将被更新)
当前配置
<property name="driverClass" value="${DriverClass}" />
<property name="jdbcUrl" value="${ReadWriteDatabaseURL}${AccountDatabaseName}${JDBCProperties}" />
<property name="user" value="${ReadWriteDatabaseCredentials}.principal" />
<property name="password" value="${ReadWriteDatabaseCredentials}.credential" />
<property name="testConnectionOnCheckout" value="true"/>
<property name="testConnectionOnCheckin" value="false" />
<property name="preferredTestQuery" value="update existing_table set value = now() where id = 1;"/>
<property name="maxIdleTime" value="44000"/>
<property name="idleConnectionTestPeriod" value="30"/>
<property name="maxStatements" value="50"/>
<property name="minPoolSize" value="3"/>
<property name="maxPoolSize" value="3"/>
<property name="acquireIncrement" value="2"/>
<property name="checkoutTimeout" value="15000"/>
<property name="acquireRetryDelay" value="1000"/>
有一个 preferredTestQuery 作为 select 1 from existing_table where 1 = 0
绝对没有任何问题
方法一:
在 C3P0 配置或休眠配置中 - 使用 preferredTestQuery 作为 writable 查询(类似于 insert/update 现有的 table)并在每次连接检查时执行查询(testConnectionCheckout = 真)。
不确定这是否应该是一个简单的查询来测试数据库是否启动,因为
- Insert/update 查询不起作用。可能我们需要 begin, commit transaction ?
- 错误:
org.hibernate.engine.jdbc.spi.SqlExceptionHelper: An attempt by a client to checkout a Connection has timed out.
- 多个查询不起作用。像
create table if not exists; insert into .. ; drop table ..;
- 错误:
org.hibernate.engine.jdbc.spi.SqlExceptionHelper: An attempt by a client to checkout a Connection has timed out.
方法二:
https://www.mchange.com/projects/c3p0/#configuring_connection_testing 指的是 高级用户可以通过实现 ConnectionTester 并提供 class 的完全限定名称作为 connectionTesterClassName 来定义他们希望的任何类型的连接测试。 两者都不是我确定如何做到这一点,也不知道它是否适用于 writable calls
上述错误的堆栈跟踪:
Caused by: org.hibernate.exception.GenericJDBCException: Could not open connection
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:221) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:157) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.internal.SessionImpl.connection(SessionImpl.java:550) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:450) ~[spring-orm-4.3.20.RELEASE.jar:4.3.20.RELEASE]
... 42 more
Caused by: java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118) ~[mchange-commons-java-0.2.10.jar:0.2.10]
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77) ~[mchange-commons-java-0.2.10.jar:0.2.10]
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:690) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource.getConnection(AbstractRoutingDataSource.java:164) ~[spring-jdbc-4.3.20.RELEASE.jar:4.3.20.RELEASE]
at org.hibernate.service.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:141) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:292) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:214) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:157) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.internal.SessionImpl.connection(SessionImpl.java:550) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:450) ~[spring-orm-4.3.20.RELEASE.jar:4.3.20.RELEASE]
... 42 more
Caused by: com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool@4c86da0c -- timeout at awaitAvailable()
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1467) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:644) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:554) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:758) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:685) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource.getConnection(AbstractRoutingDataSource.java:164) ~[spring-jdbc-4.3.20.RELEASE.jar:4.3.20.RELEASE]
at org.hibernate.service.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:141) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:292) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:214) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:157) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.internal.SessionImpl.connection(SessionImpl.java:550) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:450) ~[spring-orm-4.3.20.RELEASE.jar:4.3.20.RELEASE]
... 42 more
谢谢
我无法对更大的故障转移问题发表评论,但您当然可以定义一个 ConnectionTester
,它基本上可以满足您的任何需求。
有关简明说明,请参阅 apidocs for the UnifiedConnectionTester
interface。
c3p0
的 built-in ConnectionTester 使用 Statement.executeQuery(...)
,因此 INSERT
s 等可能无法工作。您的自定义 ConnectionTester
可以为所欲为。如果 preferredTestQuery
和 rootCauseOutParamHolder
设置为 null
(在任一方法中),您应该确定它会做一些正常的事情。
如果您愿意,可以忽略 preferredTestQuery
,或要求它为空(即,如果设置了 preferredTestQuery
,则抛出 Exception
)。
当前设置:
服务主机 (Java) 连接到 (JDBC) 主数据库 (MySQL) 并有一个从属(只读)以确保可靠性
场景:
如果翻转,我需要将slave升级为新的master。当前主控变为只读,新主控提升为读写。我希望使用测试查询(对数据库执行 writable 查询)自动将 C3P0 连接池刷新到新主服务器。
想法:
探索一种自动刷新JDBC连接池的方法,以便在发生翻转时连接到新的master(当前master将是RO,slave将被提升为RW,master cname将被更新)
当前配置
<property name="driverClass" value="${DriverClass}" />
<property name="jdbcUrl" value="${ReadWriteDatabaseURL}${AccountDatabaseName}${JDBCProperties}" />
<property name="user" value="${ReadWriteDatabaseCredentials}.principal" />
<property name="password" value="${ReadWriteDatabaseCredentials}.credential" />
<property name="testConnectionOnCheckout" value="true"/>
<property name="testConnectionOnCheckin" value="false" />
<property name="preferredTestQuery" value="update existing_table set value = now() where id = 1;"/>
<property name="maxIdleTime" value="44000"/>
<property name="idleConnectionTestPeriod" value="30"/>
<property name="maxStatements" value="50"/>
<property name="minPoolSize" value="3"/>
<property name="maxPoolSize" value="3"/>
<property name="acquireIncrement" value="2"/>
<property name="checkoutTimeout" value="15000"/>
<property name="acquireRetryDelay" value="1000"/>
有一个 preferredTestQuery 作为 select 1 from existing_table where 1 = 0
绝对没有任何问题
方法一:
在 C3P0 配置或休眠配置中 - 使用 preferredTestQuery 作为 writable 查询(类似于 insert/update 现有的 table)并在每次连接检查时执行查询(testConnectionCheckout = 真)。 不确定这是否应该是一个简单的查询来测试数据库是否启动,因为
- Insert/update 查询不起作用。可能我们需要 begin, commit transaction ?
- 错误:
org.hibernate.engine.jdbc.spi.SqlExceptionHelper: An attempt by a client to checkout a Connection has timed out.
- 错误:
- 多个查询不起作用。像
create table if not exists; insert into .. ; drop table ..;
- 错误:
org.hibernate.engine.jdbc.spi.SqlExceptionHelper: An attempt by a client to checkout a Connection has timed out.
- 错误:
方法二: https://www.mchange.com/projects/c3p0/#configuring_connection_testing 指的是 高级用户可以通过实现 ConnectionTester 并提供 class 的完全限定名称作为 connectionTesterClassName 来定义他们希望的任何类型的连接测试。 两者都不是我确定如何做到这一点,也不知道它是否适用于 writable calls
上述错误的堆栈跟踪:
Caused by: org.hibernate.exception.GenericJDBCException: Could not open connection
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:221) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:157) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.internal.SessionImpl.connection(SessionImpl.java:550) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:450) ~[spring-orm-4.3.20.RELEASE.jar:4.3.20.RELEASE]
... 42 more
Caused by: java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118) ~[mchange-commons-java-0.2.10.jar:0.2.10]
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77) ~[mchange-commons-java-0.2.10.jar:0.2.10]
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:690) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource.getConnection(AbstractRoutingDataSource.java:164) ~[spring-jdbc-4.3.20.RELEASE.jar:4.3.20.RELEASE]
at org.hibernate.service.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:141) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:292) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:214) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:157) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.internal.SessionImpl.connection(SessionImpl.java:550) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:450) ~[spring-orm-4.3.20.RELEASE.jar:4.3.20.RELEASE]
... 42 more
Caused by: com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool@4c86da0c -- timeout at awaitAvailable()
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1467) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:644) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:554) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:758) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:685) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140) ~[c3p0-0.9.5.1.jar:0.9.5.1]
at org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource.getConnection(AbstractRoutingDataSource.java:164) ~[spring-jdbc-4.3.20.RELEASE.jar:4.3.20.RELEASE]
at org.hibernate.service.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:141) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:292) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:214) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:157) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.hibernate.internal.SessionImpl.connection(SessionImpl.java:550) ~[hibernate-core-4.2.2.Final.jar:4.2.2.Final]
at org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:450) ~[spring-orm-4.3.20.RELEASE.jar:4.3.20.RELEASE]
... 42 more
谢谢
我无法对更大的故障转移问题发表评论,但您当然可以定义一个 ConnectionTester
,它基本上可以满足您的任何需求。
有关简明说明,请参阅 apidocs for the UnifiedConnectionTester
interface。
c3p0
的 built-in ConnectionTester 使用 Statement.executeQuery(...)
,因此 INSERT
s 等可能无法工作。您的自定义 ConnectionTester
可以为所欲为。如果 preferredTestQuery
和 rootCauseOutParamHolder
设置为 null
(在任一方法中),您应该确定它会做一些正常的事情。
如果您愿意,可以忽略 preferredTestQuery
,或要求它为空(即,如果设置了 preferredTestQuery
,则抛出 Exception
)。