警告 c3p0:发生另一个错误:连接已关闭

WARNING c3p0: Another error has occurred: Connection is Closed

我们在 Microsoft SQL 数据库的应用程序中使用 c3p0 作为连接池。连接在结帐时使用验证查询进行测试,因此应用程序无法使用过时的连接。

最近,我们开始在应用程序日志中看到以下警告(很多此类消息按顺序出现)。任何人都见过这种异常,这是什么意思?

2017-03-29 09:34:24 [WARNING] [c3p0] A PooledConnection that has already signalled a Connection error is still in use!
2017-03-29 09:34:24 [WARNING] [c3p0] Another error has occurred [ com.microsoft.sqlserver.jdbc.SQLServerException: The connection is closed. ] which will not be reported to listeners!
2017-03-29 09:34:24 com.microsoft.sqlserver.jdbc.SQLServerException: The connection is closed.
2017-03-29 09:34:24     at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:190)
2017-03-29 09:34:24     at com.microsoft.sqlserver.jdbc.SQLServerConnection.checkClosed(SQLServerConnection.java:388)
2017-03-29 09:34:24     at com.microsoft.sqlserver.jdbc.SQLServerConnection.prepareStatement(SQLServerConnection.java:2166)
2017-03-29 09:34:24     at com.microsoft.sqlserver.jdbc.SQLServerConnection.prepareStatement(SQLServerConnection.java:1853)
2017-03-29 09:34:24     at com.mchange.v2.c3p0.impl.NewProxyConnection.prepareStatement(NewProxyConnection.java:1076)

我的顾虑是:

  1. 此警告(或异常消息)是否意味着查询实际执行失败并且代码将抛出异常?
  2. 这只是 c3p0 记录的一条警告消息吗,因为我们在结帐时测试了连接,并且由于连接已关闭,它现在将从数据库获取一个新连接并且应用程序将 运行问题?

如有任何帮助,我们将不胜感激。谢谢!

因此,这里没有足够的信息来说明问题的最初原因是什么。任何事情都可能发生,网络中断等等。在结帐时测试连接可确保连接在结帐时有效,但一旦进入客户端,就无法阻止中断。它应该非常好,除非您长时间保持 Connections 检出状态。 (不要那样做!使用连接池,采用及时、快速签出、立即签入策略。)

无论如何,应用程序使用 Connection 的某些尝试引发了异常。然后 c3p0 在内部检查连接,确定连接已断开,并发出一个事件(由 JDBC 规范指定,但仅内部侦听器感兴趣)指示连接错误。 c3p0 通过在应用程序完成时将连接标记为销毁而不是签入来对此作出响应。

应用程序尽管看到了第一个异常,但仍继续使用连接。发生了第二个异常(是的,这个连接真的坏了)。这就是 c3p0 在这里记录的内容。它忽略了第二个异常,而不是发出连接错误信号,因为已经为此连接发出了连接错误信号。但是有点惊讶和恼火的发现Connection还在使用;)

所有异常都转发给应用程序。默默地吞下问题与 c3p0 的理念截然相反。但是无论您的应用程序使用此连接做什么都触发了异常,并且您的应用程序继续执行其他触发更多的事情。

这并不一定意味着有任何问题。应用程序可能会暂时将 Exception 解释为 Connection 失败以外的事情。也许由于违反约束而发生异常,如果是这样,是否有解决方法?如果是这样的话,应用程序会在这里找到进一步的证据,是的,Connection 被破坏了,因为在处理了先前的 Exception 之后,下一次使用 Connection 将继续失败。

如果我是你,我会查看触发此堆栈跟踪的应用程序代码,并特别注意先前步骤中可能过于宽容的异常处理,这可能 catch 一个异常并在以下情况下继续它应该中止。同样,情况不一定如此——可能是您的应用程序正在做它应该做的事情,它正在适当地重试或尝试在潜在可恢复的错误后继续,并且它对重试也会失败的可能性很稳健,在这种情况下万一你会在你的日志中无害地看到这些堆栈跟踪,希望很少,当已经签出的连接失败时。但我肯定会在触发堆栈跟踪的步骤中,以及重要的是在可能触发第一个异常的先前步骤中,在此代码路径中检查您的异常处理逻辑。通常一个异常会中止数据库代码路径(除了最终的 rollback()close()),这里你正在继续第二个,这可能很棒,但要确保它是你想要做的.

如果您经常看到这种情况,请确保结帐时的连接测试确实配置正确,然后尽量减少连接结帐的时间,然后尝试了解为什么您的网络或服务器上的某些东西side 可能偶尔会失败。