【问题标题】:No operations after closed connection, bypassing my check for a closed connection?关闭连接后没有操作,绕过我对关闭连接的检查?
【发布时间】:2013-03-21 18:52:22
【问题描述】:

我的代码循环遍历描述需要存储在 MySQL 数据库中的信息的对象队列。我最近稍微更改了代码以关闭整个应用程序中 finally 块中的连接,以便在发生异常时不会泄漏任何内容。它很好用,除了:

有些用户有时会看到错误No operations allowed after resultset closed - 我知道错误的含义,但我不知道如何关闭它。

违规代码:

    PreparedStatement s = null;
    Connection conn = null;

    try {

        if( !queue.isEmpty() ){

            conn = Prism.dbc();
            if(conn == null || conn.isClosed()){
                return;
            }
            conn.setAutoCommit(false);
            s = conn.prepareStatement("INSERT query goes here");
            int i = 0;
            while (!queue.isEmpty()){
                Handler a = queue.poll();
                if( a == null || a.isCanceled() ) continue;
                // .. value setting code here
                s.addBatch();
                if ((i + 1) % perBatch == 0) {
                    s.executeBatch(); // Execute every x items.
                }
                i++;
            }

            s.executeBatch();
            conn.commit();

        }
    } catch (SQLException e) {
        // error logging code
    } finally {
        if(s != null) try { s.close(); } catch (SQLException e) {}
        if(conn != null) try { conn.close(); } catch (SQLException e) {}
    }

错误指向conn.setAutoCommit(false); 行。但是,我不知道此时如何关闭连接,因为我正在明确检查其上方的已关闭/空连接。

【问题讨论】:

  • 你能用sql客户端连接db并执行查询吗?
  • 这发生在用户身上,我无法确定重现它的原因 - 但那些报告它的人从未遇到过这个问题,直到我将应用程序更改为使用 finally 块。我很确定这不是他们的数据库的问题 - 因为重新启动我们的应用程序会重置连接。
  • 我怀疑 finally 是否与它有关。这可能是 db 驱动程序问题 [因为不同用户使用的驱动程序可能不同]。我建议让用户使用 SQL 客户端连接到数据库,如果可行,请确保所有用户都安装了相同的数据库驱动程序。
  • 你能提供整个堆栈跟踪吗?
  • 最近遇到此问题的用户的堆栈:pastebin.com/TE5vBNkq - 链接到发生错误的源(代码如上)github.com/prism/Prism/blob/master/src/main/java/me/botsko/…

标签: java mysql jdbc


【解决方案1】:

此问题最可能的原因是 JDK 版本与所使用的 DB 驱动程序不兼容。

查看此链接:http://dev.mysql.com/downloads/connector/j,它提供了各种版本的 DB 驱动程序。

编辑:

查看 jdk 和驱动映射的链接:http://dev.mysql.com/doc/refman/5.1/en/connector-j-versions-java.html

编辑:

我之所以说这是最可能的原因,是因为与 DB 合作的经验。我不认为这是代码问题,因为它对某些人有用。使用不兼容的驱动程序可能会导致奇怪的问题,例如您所面临的问题。 我在使用 Oracle DB 时遇到过这样的问题,我能够执行所有查询,但合并查询导致连接关闭,问题是由于驱动程序不兼容造成的。

所以我是根据我的经验这么说的。

我也觉得即使这不是问题的确切原因[它最可能的问题原因]如果用户可以发布驱动程序版本和 jdk 版本我们肯定可以排除这种情况,这篇文章肯定可以帮助人们,所以我看不出投反对票的理由。

【讨论】:

  • 我猜在这种情况下错误会更频繁地发生,如果不是总是这样的话。
  • 为什么这是最可能的原因?
  • @Skirsch:为什么?这取决于您的驱动程序,所以如果只有一个用户有错误的驱动程序,那么它只会发生在一个用户身上。
  • 我会要求删除不赞成票或说明反对票的原因
  • @Lokesh:我最初的印象是这是一个客户端-服务器-应用程序,其中只涉及一个驱动程序;那是服务器之一。但是由于客户端似乎直接连接到数据库,驱动程序问题可能是相关的,真的。但是 a) 我假设该软件随驱动程序一起提供 - BotskoNet:请您确认/拒绝吗? b)我仍然希望问题更加一致,驱动程序错误的用户应该经常遇到问题。而且我没有投反对票:O
【解决方案2】:

我在堆栈跟踪中发现的核心问题是: 2013-03-31 13:21:11 [SEVERE] Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 30,491,788 milliseconds ago. The last packet sent successfully to the server was 30,491,788 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.

调用Prism.dbc();时得到的连接实际上是来自连接池的一个;在这种特定情况下,池连接中断。它表示池中的 JDBC 连接与数据库之间的通信超过 8 小时没有成功。可能是因为在数据库服务器上定义了提到的wait_timeout,或者防火墙断开了连接或其他原因;连接中断的原因可能有很多。

您应该按照异常提出的建议来解决此问题。

【讨论】:

  • 所以这是我遇到的问题 - 如果我为我的应用程序编写代码来检测此错误,以便我可以自动关闭并重新连接数据库连接 - 它总是作为异常发生。这意味着用户操作将失败,我们将重新连接到数据库,但随后用户必须再次激活查询。在让他们的查询失败之前,我需要找到一种方法来重新建立与数据库的连接——我能想到的唯一方法是使用某种测试查询。建议?
  • 在您的 Prism.initDbPool 方法中,您可以为您的池设置一些额外的配置参数,例如setTestOnBorrow(true)(这将导致池在提供Connection 之前运行验证查询)。一定要设置验证查询。请注意,这会带来某种性能损失,因为执行验证查询显然需要一些时间。对于 MySQL,SELECT 1 就足够了。您应该查看tomcat.apache.org/tomcat-7.0-doc/api/org/apache/tomcat/jdbc/… 以了解可能的情况。
  • 在您的情况下,您最好使用testWhileIdlevalidationInterval 的适当值...也许在打开testOnBorrow 之前尝试这个。
  • 我领先一步,刚刚将它添加到应用程序的开发版本中 - 但我担心如果验证查询不起作用,我不清楚池会做什么。文档说它会抛出连接并尝试获取另一个连接,但如果应用程序已经闲置了几个小时,它们可能都过时了。验证查询系统是否以某种方式强制建立与数据库的新连接?还是我仍然需要检测“关闭连接”异常并自己运行完整的重新连接代码...
  • 你真的应该读到这个:people.apache.org/~fhanik/jdbc-pool/jdbc-pool.html 池总是会尝试返回一个有效的连接。当您使用testWhileIdle 时,无论如何您都不会与池交互,它在后台运行。如果您使用testOnBorrow 并且池获取断开的连接,它将尝试为您提供另一个连接。如果第二个也被破坏 - 好吧,我想你需要看看代码。但无论如何,你比现在过得更好。也许将maxAge 的值设置为 4h 左右就足够了。我猜你可以去任何一种方式。
猜你喜欢
  • 2012-06-06
  • 2019-07-27
  • 1970-01-01
  • 2018-12-28
  • 2020-04-17
  • 1970-01-01
  • 2019-06-26
  • 1970-01-01
  • 2011-11-25
相关资源
最近更新 更多