Java 如何重置JDBC连接池

Java 如何重置JDBC连接池,java,tomcat,jdbc,connection-pooling,Java,Tomcat,Jdbc,Connection Pooling,我有一个问题,在通过tomcat web应用程序应用户请求重置MySQL数据库后,我会收到tomcat异常。到目前为止,我已尝试将其分解为设置、问题和我的分析,以帮助任何试图阅读本文的人 安装程序 重置基本上包括从java代码调用bash脚本以: 删除根mysql用户密码 加载旧版本的数据库 在上面运行一些脚本 还原所有密码 这是一个用户启动的过程,通常用于将数据库恢复到以前的状态,但也可用于从另一个系统导入数据库。一旦一切完成,用户然后尝试访问web应用程序的不同部分(即,在不注销/重新登

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

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

  • 删除根mysql用户密码
  • 加载旧版本的数据库
  • 在上面运行一些脚本
  • 还原所有密码
这是一个用户启动的过程,通常用于将数据库恢复到以前的状态,但也可用于从另一个系统导入数据库。一旦一切完成,用户然后尝试访问web应用程序的不同部分(即,在不注销/重新登录的情况下使用相同会话),该部分执行DB查询以获取一些数据

问题 tomcat应用程序查询数据库后,会出现异常:

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)
即使用户注销并重新登录,我也会看到此异常。如果我刷新页面四次,页面每次都会加载多一点,但会出现一些不同的异常(上面的所有变体-由“EOFEException:Can not read response from server”引起的CommunicationsException)。最后一次,一切似乎都正常运行

要避免这些异常,我唯一能做的就是重新启动tomcat。我希望避免这种情况,因为这将意味着当前登录的用户将丢失会话,并且必须等待tomcat重新启动才能重新登录。强迫他们注销/重新登录可能是一个可以接受的折衷方案,但这并不能解决问题

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

server.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"/>
我认为连接池包含过时/失效的连接。每当我获得与
ds.getConnection
的连接时,它就会获得这些旧连接中的一个。第一次尝试使用它将失败,连接将被重置(请注意,我使用的是
autoReconnect=true
,因此第二次应该(并且确实)起作用)。但是,池中包含许多(在我的例子中,经验上是4或5个)陈旧的连接,因此需要一段时间才能正确重置它们。重置连接后,一切正常

解决? 因为我使用了
autoReconnect=true
我可以重新构造我的代码,这样如果我在尝试查询时遇到异常,我就可以重试查询一次。如果它再次失败,那么我就会知道确实存在问题。如果通过,则连接已成功重新建立

问题是代码中到处都有查询。重新分解它们将需要大量的时间和测试,如果有必要,我会这样做,但我希望避免。此外,如果查询因其他原因失败,则在报告之前将尝试两次。对于长时间的查询,这可能会有显著的用户体验延迟,但仅在错误情况下

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

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


谢谢大家的时间和帮助

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

默认情况下,Tomcat=7

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

validationQuery=<TEST SQL>
testOnBorrow=true
validationQuery=TEST SQL
testOnBorrow=true
validationQuery=
testOnBorrow=true

由于您的项目包含多个类似(
ojdbc6或ojdbc14
)的
ojdbc
jar,将引发该异常此时,当您尝试连接oracle
12c
删除项目中的所有
ojdbc
jar并添加任何一个jar时,可能会出现异常。建议您在从池中获取之前测试连接

外接程序连接池配置:

validationQuery=<TEST SQL>
testOnBorrow=true
validationQuery=TEST SQL
testOnBorrow=true

解决方案:不要删除您在数据库连接池中配置的用户的凭据。事实上,您不应该为了改变数据库的状态而弄乱mysql用户数据。您应该只更改正在使用的架构。@LuiggiMendoza谢谢。我曾经想过,但长话短说,这可能不是一个选择。运行的脚本没有修改数据库的凭据,因此我需要删除root用户的密码。另外,加载的新数据库可能有不同的密码。我曾想过,但长话短说,这可能不是一个选项,然后默默忍受。除此之外,您无法重置数据库连接池。避免这样做,或者使用有足够能力执行脚本的用户来执行脚本。你可以创建另一个用户来执行此操作,或者关闭你的应用程序并重新启动它们,并为此制定策略。我猜你的整个方法都会给你带来这个问题,而你正试图使用肮脏的伎俩来解决你的设计。我的建议是:是的,将这个密码作为参数发送到脚本中,并且忘记甚至弄乱mysql用户凭据。这就是问题所在,无论您如何描述它,您都应该避免这一步,并使用更干净的设计。如果您了解数据库连接池的工作原理,那么如果您重新启动数据库引擎,您不应该对这一结果感到惊讶。同样,解决方案不是重置连接池,而是建立策略以重新启动数据库引擎。如果你要重新启动你的