【问题标题】:Database access fails to work in the morning早上数据库访问失败
【发布时间】:2013-06-14 13:49:48
【问题描述】:

我正在构建一个登录系统。当我只是在我自己的电脑上测试它时,它工作得非常好。一旦我将它上传到我们的服务器,我们就开始遇到问题......它在早上几秒钟内无法登录。其余时间都可以正常工作。

我昨天和今天才遇到这个,每天早上只能测试一次,所以还很难提供太多细节。这是设置:

首页是一个使用javascript和angular js的html页面。它会弹出一个空框架,然后对页面内容发出 ajax 请求。在任何返回值为“访问权限不足”的失败 ajax 请求上,它将取消隐藏持有登录表单的div。该登录表单将页面清空并提供一个提交按钮。单击提交按钮后,它会向 Java 服务器发送一个 ajax 登录请求。一旦该请求被返回,页面将再次隐藏登录表单,一切照常进行。

在后端,我们有一个运行在 1.6 和 1.7 之间的 Java 服务器(是的,我知道,我应该知道得更好 - 服务器报告它是 1.7.001,但是 1.7 的功能就像基于字符串的 switch-case语句不起作用,所以我们在上传时编译为 1.6 java。这是我们正在处理的一个已知问题。)我们正在使用 Stripes 来做前端代码。数据库为mysql数据库,位于同一台服务器上。

发生此错误时,总是早上第一次登录。我加载页面,输入用户/密码,然后单击登录。页面闪烁并返回登录屏幕。登录后我还没有清除用户/通行证,因为我们仍处于测试阶段,所以我可以再次点击“登录”,然后再点击十几次,最终登录。这个问题有只发生了两次:昨天和今天,早上的第一次登录。

我的同事在以前的项目中使用另一个类似的设置,在同一台服务器上遇到了类似的问题。他说他认为问题与 sql server 关闭连接而 java server 没有意识到连接已关闭有关,但他不确定,也不知道如何解决。

我什至不知道要提供什么其他信息,要显示什么代码,或者类似的东西。我能在任何地方找到的最好的建议是“设置一个预定的事件,每隔几个小时发出一次可靠的数据库请求”,但这看起来很……笨拙。如果有人可以帮助我,我希望能够测试更明确的问题和解决方案。如果有人能告诉我他们希望看到什么代码来解决这个问题,我很乐意将其粘贴。更多信息?问一下。范围似乎如此... ...我不知道哪些部分可能是相关的。

编辑 1:错误代码!

[ERROR] - Database Error 1 on verify
java.sql.SQLException: Already closed.
    at org.apache.tomcat.dbcp.dbcp.PoolableConnection.close(PoolableConnection.java:114)
    at org.apache.tomcat.dbcp.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.close(PoolingDataSource.java:191)

编辑 2:连接代码

这是来自我们专门为所有 mysql 数据库连接保留的对象。

private static ConnectionSource coreConnection = null;
private static DataSource coreDataSource = null;

public static ConnectionSource getCoreConnection() throws SQLException, NamingException {
    if (coreConnection == null || !coreConnection.isOpen()) {        
        Context env = (Context)new InitialContext().lookup("java:comp/env");        
        coreDataSource = (DataSource)env.lookup("webapps/test");
        coreConnection = new DataSourceConnectionSource(coreDataSource, new MysqlDatabaseType());
    }
    return coreConnection;
}

【问题讨论】:

  • 这听起来像是某种超时问题。您在 Java 代码中使用什么驱动程序连接到 MySQL?您是在为所有查询重复使用单个连接,还是时不时地创建一个新连接?
  • @WouterH 我认为您的第一印象是正确的。我敢打赌,数据库至少会在几个小时后关闭空闲连接。
  • @WouterH 我包含了错误消息和连接代码。我正在为所有查询重新使用单个连接。是的,我认为数据库会在几个小时后关闭空闲连接。我正在查看您的链接,我认为它很有用...
  • @WolfmanJoe 异常本身非常普遍,是的。您可以使用 getMessage()、getErrorCode() 和 getSQLState() 来查找识别信息以检测此变体。建立防止无限递归的保护也可能是一个好主意,例如通过抛出异常在几次尝试后放弃。另见docs.oracle.com/javase/6/docs/api/java/sql/SQLException.html

标签: java mysql stripes


【解决方案1】:

配置您的连接池以验证连接。然后,连接池将向数据库发送一个简单的查询(您在配置期间指定)。如果该查询失败,它将关闭连接并为您提供一个新连接,否则它将就地使用它。这有助于解决此类问题以及数据库在服务器背后出现故障的问题。

【讨论】:

  • 这可能会在一次通话中发生多次。是否值得在对象上拥有一个“最后验证的”私有属性并仅在例如半小时或一个小时过去时才验证连接?或者测试的成本是否足够小以至于它并不重要?
  • 作为说明,我可能会将其标记为答案,但我需要运行一些测试以确保它是答案。一旦我确定它正常工作(可能会在下周发生),我会标记它是正确的。
  • 它只会在您从池中请求连接时验证连接。显然,如果在处理过程中连接出现问题,您将不得不处理该问题。您可以在代码中处理这些情况,或者您可以关闭连接并要求一个新的“新鲜”连接。如果你有一个特别长的过程发生,后者更有意义。当然,如果关闭连接,则需要与数据库启动新事务。
【解决方案2】:

MySQL 关闭已打开很长时间的连接,但不做任何事情。根据您的描述,听起来这就是您要遇到的情况。

第一次登录失败,因为它发现使用的数据库连接不再工作,驱动程序也注意到了这一点。然后驱动程序将为下一个请求使用新连接。

想到的第一种处理方法是检测此 SQLException,并通过使用相同查询打开新连接来处理它。您正在使用的驱动程序中可能还有其他可用的解决方案,但不幸的是,我不知道有任何解决方案。

为了帮助检测此 SQLException,您可以查看 the docs,并评估其中列出的方法是否返回此错误所特有的任何内容。

如果您使用的是连接池,那么this question 可能包含保持连接活动的答案。

【讨论】:

  • 我不确定我是否喜欢只响应 SQLExceptions 的想法,因为这会将代码传播到整个系统。我可能会更多地接受 Will Hartung 关于测试连接的上述建议,但非常感谢您在诊断问题和提供更多信息方面的帮助! +1
  • @WolfmanJoe 请看我回答的最后一句,这似乎是特定于 dbcp 的,你似乎正在使用它;)但是,如果你能做到这一点,肯定会这样做。我只是在对您的问题进行了更多搜索后才发现这一点,这就是我没有开始使用它的原因。
  • 是的,我正在看,它似乎非常有用。再次感谢你。 :)
猜你喜欢
  • 1970-01-01
  • 2018-11-11
  • 1970-01-01
  • 2016-07-05
  • 1970-01-01
  • 2021-11-07
  • 2014-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多