当连接变坏时,有啥方法可以让 JBoss 连接池重新连接到 Oracle?
Posted
技术标签:
【中文标题】当连接变坏时,有啥方法可以让 JBoss 连接池重新连接到 Oracle?【英文标题】:Is there any way to have the JBoss connection pool reconnect to Oracle when connections go bad?当连接变坏时,有什么方法可以让 JBoss 连接池重新连接到 Oracle? 【发布时间】:2010-09-12 19:31:36 【问题描述】:我们的 JBoss 和 Oracle 在不同的服务器上。连接似乎已断开,并导致 JBoss 出现问题。如果连接不好,我如何让 JBoss 重新连接到 Oracle,而我们首先要弄清楚为什么连接会被丢弃?
【问题讨论】:
【参考方案1】:虽然您可以使用旧的“从双重选择 1”技巧,但这样做的缺点是每次从池中借用连接时都会发出额外的查询。对于大容量,这是一种浪费。
JBoss 提供了一个特殊的连接验证器,应该用于 Oracle:
<valid-connection-checker-class-name>
org.jboss.resource.adapter.jdbc.vendor.OracleValidConnectionChecker
</valid-connection-checker-class-name>
这利用了 Oracle JDBC Connection 类上的专有 ping() 方法,并使用驱动程序的底层网络代码来确定连接是否仍然有效。
但是,每次借用连接时都运行它仍然很浪费,因此您可能希望使用后台线程检查池中连接并静默丢弃死连接的工具。这样效率更高,但意味着如果连接确实死了,在后台线程运行检查之前使用它们的任何尝试都将失败。
查看wiki docs了解如何配置后台检查(查找background-validation-millis
)。
【讨论】:
'Select 1 from dual' 和 org.jboss.resource.adapter.jdbc.vendor.OracleValidConnectionChecker 方法是等价的,尽管连接检查确实提供了一个抽象级别。我们必须反编译 oracle jdbc 驱动程序以进行故障排除练习,Oracle 在连接检查中使用的 ping 的内部实现是执行“Select 'x' from dual”。纳奇。 请注意,OracleValidConnectionChecker
在 JBoss AS 4 和 5 中有一个 minor bug。我还记得由于在后台使用单独的 pinger 线程,它在高并发负载下存在性能问题。
@abh 我们遇到了同样的问题,发现同样的事情,pingDatabase()
将使用SELECT 'x' FROM DUAL;
查询数据库【参考方案2】:
池中通常有一个配置选项,可以在借用时执行验证查询。如果验证查询成功执行,池将返回该连接。如果查询未成功执行,池将创建一个新连接。
JBoss Wiki 记录了池的各种属性。
<check-valid-connection-sql>select 1 from dual</check-valid-connection-sql>
看起来应该可以解决问题。
【讨论】:
如果您的 cfg 中已经有该行,还要检查您没有将“匹配时验证”和“背景验证”都设置为 false(请参阅链接的 wiki 页面详细信息)。【参考方案3】:评论没有足够的代表,所以它是一个答案的形式。 'Select 1 from dual'
和 skaffman 的 org.jboss.resource.adapter.jdbc.vendor.OracleValidConnectionChecker
方法是等效的,尽管连接检查确实提供了一定程度的抽象。我们必须反编译 oracle jdbc 驱动程序以进行故障排除练习,Oracle 的 ping 内部实现是执行'Select 'x' from dual'
。纳奇。
【讨论】:
不等同于使用valid-connection-checker
与供应商提供的正确类通常针对特定的数据库管理系统进行了优化【参考方案4】:
JBoss 提供了 2 种方式来验证连接: - 基于 Ping 的 AND - 基于查询
您可以根据需要使用。这是由单独的线程根据数据源配置文件中定义的持续时间安排的。
<background-validation>true</background-validation> <background-validation-minutes>1</background-validation-minutes>
有时如果您在 Jboss 上没有正确的 oracle 驱动程序,您可能会收到 classcast 或相关错误,并且该连接可能会开始从连接池中丢失。您可以尝试通过实现org.jboss.resource.adapter.jdbc.ValidConnectionChecker
接口来创建自己的 ConnectionValidator 类。此接口仅提供单一方法“isValidConnection()
”,并期望“NULL”作为有效连接的回报。
例如:
public class OracleValidConnectionChecker implements ValidConnectionChecker, Serializable
private Method ping;
// The timeout (apparently the timeout is ignored?)
private static Object[] params = new Object[] new Integer(5000) ;
public SQLException isValidConnection(Connection c)
try
Integer status = (Integer) ping.invoke(c, params);
if (status.intValue() < 0)
return new SQLException("pingDatabase failed status=" + status);
catch (Exception e)
log.warn("Unexpected error in pingDatabase", e);
// OK
return null;
【讨论】:
【参考方案5】:对@skaffman 的回答稍作更新。在 JBoss 7 中,您必须在设置有效连接检查器时使用“类名”属性,并且包也不同:
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleValidConnectionChecker" />
【讨论】:
【参考方案6】:我们最近遇到了一些浮动请求处理失败,原因是孤立的 oracle DBMS_LOCK
会话锁无限期地保留在客户端连接池中。
所以这是一个强制会话在 30 分钟内到期但不影响应用程序运行的解决方案:
<check-valid-connection-sql>select case when 30/60/24 > sysdate-LOGON_TIME then 1 else 1/0 end
from V$SESSION where AUDSID = userenv('SESSIONID')</check-valid-connection-sql>
这可能会导致从池中获取连接的过程变慢。确保在负载下进行测试。
【讨论】:
老兄,这太漂亮了。 30/60/24 代表什么? 答案:这是一种将 30 秒除以 60 分钟除以 24 小时的方法,这是时间使用的格式。 @Vadzim 此方法会在连接重新连接时引发异常。有什么方法可以让它不抛出异常并在不失败的情况下恢复它的请求? @Nicholas,似乎unlike with Tomcat 抛出异常是 JBoss 连接验证失败的唯一方法。您可以使用自定义 log4j 过滤器在日志中抑制它。否则是无害的。在登记处理任何实际请求之前,对连接进行验证。以上是关于当连接变坏时,有啥方法可以让 JBoss 连接池重新连接到 Oracle?的主要内容,如果未能解决你的问题,请参考以下文章
当数据集很大时,有啥技巧可以避免或降低一对多连接和非等连接的成本?
当Jboss服务器尝试从HypersonicDB数据源获取连接时,它会挂起
为啥要使用 JSTL?当我们在 JSP 文件中使用带有连接字符串的数据库连接来获取从 servlet 发送的数据时会有啥危害[重复]