gpt4 book ai didi

java - 如何重置 JDBC 连接池

转载 作者:搜寻专家 更新时间:2023-10-31 20:01:56 25 4
gpt4 key购买 nike

我遇到一个问题,在我通过 tomcat 网络应用程序应用户请求重置我的 MySQL 数据库后,我遇到了 tomcat 异常。到目前为止,我已尝试将其分解为设置、问题和我的分析,以帮助任何试图阅读本文的人。

设置

重置基本上包括从 java 代码调用 bash 脚本以:

  • 删除 root mysql 用户密码
  • 加载旧版本的数据库
  • 在上面运行一些脚本
  • 恢复所有密码

这是一个用户启动的过程,通常将数据库恢复到以前的状态,但它也可用于从另一个系统导入数据库。一切都完成后,用户将尝试访问 Web 应用程序的不同部分(即使用相同的 session 而不注销/重新登录),这会执行数据库查询以获取一些数据。

问题

一旦tomcat应用查询DB,出现异常:

Dec 29, 2014 3:49:50 PM ERROR BasicSecurityRealm:216 - 
ERROR: ----- SQLException -----

Dec 29, 2014 3:49:50 PM INFO BasicSecurityRealm:218 - Exceptioncom.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 234,810 milliseconds ago. The last packet sent successfully to the server was 12 milliseconds ago.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
...
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2540)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2990)

即使用户注销并重新登录,我也会看到这个异常。如果我刷新页面四次​​,页面每次都会加载更多一些,但会出现一些不同的异常(上述所有变体 - 由“EOFException:无法从服务器读取响应”引起的 CommunicationsException)。最后一次,一切似乎都在正常运行。

要避免这些异常,我唯一能做的就是重新启动 tomcat。我想避免这种情况,因为这意味着当前登录的用户将失去他们的 session ,并且必须等待 tomcat 重新启动才能重新登录。强制他们注销/重新登录可能是一个可以接受的妥协,但这并不能解决问题。

分析

据我所知,我认为问题与 JDBC 连接池有关。我正在使用 JNDI 数据源访问我的数据库,如下所示:

服务器.xml:

  <GlobalNamingResources>
<Resource name="jdbc/mydb"
auth="Container"
type="javax.sql.DataSource"
maxActive="30" maxIdle="30" maxWait="2147483647"
username="x" password="x"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mydb?autoReconnect=true"/>

web.xml:

<!-- Data source definitions -->
<resource-ref>
<res-ref-name>jdbc/mydb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

Java:

    // Get connection to specified database
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource) envCtx.lookup("jdbc/mydb");
con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("...");

我认为连接池中包含过时/失效的连接。每当我与 ds.getConnection 建立连接时,它就会获得这些旧连接之一。第一次尝试使用它会失败,连接会重置(请注意我正在使用 autoReconnect=true,所以第二次应该(并且确实)有效)。但是,该池包含许多(在我的例子中,经验上有 4 或 5 个)失效连接,因此需要一段时间才能将它们全部正确重置。重置连接后,一切都会正常运行。

解决方案?

因为我使用了 autoReconnect=true,所以我可以重新构建我的代码,这样如果我在尝试查询时遇到异常,我可以重试一次查询。如果再失败,我就知道真的有问题了。如果通过,则连接已成功重新建立。

问题在于代码中到处都有查询。重构它们将花费大量时间和测试,如果有必要我会这样做,但我想避免。此外,如果查询由于其他原因失败,则在报告之前会尝试两次。对于长查询,这可能会导致严重的用户体验延迟,但仅限于错误情况。

另一种解决方案是强制重置/重新连接连接池中的所有连接。我可以通过编程方式(即在 bash 脚本调用完成时从我的 java 代码)或从 bash 脚本(例如使用某种类型的命令行实用程序)来执行此操作。问题是,我不知道该怎么做,或者是否可能。

我找到了一些关于拦截器的文档,但我不确定这是否适用于重置连接。我会继续调查。

感谢大家的时间和帮助!

最佳答案

您可以在从池中获取之前测试连接

默认 Tomcat <7 使用 commond-dbcp对于 Tomcat >= 7,它是 jdbc-pool

在这两种情况下,将下一个属性添加到连接池配置中:

validationQuery=<TEST SQL>
testOnBorrow=true

关于java - 如何重置 JDBC 连接池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27693147/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com