什么是java.io.EOFException,消息:无法从服务器读取响应。预计读取4个字节,读取0个字节

时间:2012-12-19 10:39:54

标签: java mysql glassfish connection pool

这个问题已经在SO中被问了几次,在其他网站上已经多次询问过。但我没有得到任何令人满意的答案。

我的问题:
我有一个java Web应用程序,它使用简单的 JDBC 通过 Glassfish 应用程序服务器连接到 mysql 数据库。

我在glassfish服务器中使用了以下配置的连接池:
初始池大小:25
最大泳池大小:100
池调整数量:2
空闲超时:300秒
最长等待时间:60,000毫秒

该应用程序已部署了3个月,并且运行良好 但是从最近2天开始,登录时会出现以下错误。

部分StackTrace

com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: No operations allowed after connection closed.Connection was implicitly closed due to underlying exception/error:  

** BEGIN NESTED EXCEPTION **  

com.mysql.jdbc.CommunicationsException  
MESSAGE: Communications link failure due to underlying exception:  

** BEGIN NESTED EXCEPTION **  

java.io.EOFException  
MESSAGE: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.  

STACKTRACE:  

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:1997)  
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2411)  
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2916)  
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1631)  
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1723)  
at com.mysql.jdbc.Connection.execSQL(Connection.java:3256)  
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1313)  
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1448)  
............  
............  
my application traces....  

突然造成这个错误的原因是什么?我已经失去了很多时间。

编辑:重启服务器后问题甚至会持续存在。根据DBA,两个重要的mysql服务器配置是:
wait_timeout: 1800秒
connect_timeout: 10秒
注意:部署在连接到同一数据库且使用不同池的同一服务器中的其他应用程序正在顺利运行。

EDIT-2:在阅读了很多内容并期待取得一些积极成果后,我对连接池进行了这些更改。

最长等待时间: 0(之前是60秒)
连接验证:必填项 验证方法:表格 表名:演示版 最多验证一次: 40秒
创建重试尝试: 1
重试间隔: 5秒
最大连接数: 5

当应用程序持续运行3天时,这很有效。但是我得到了一个非常奇怪而有趣的结果。在监控连接池时,我发现了这些数字:

NumConnAcquired: 44919伯爵 NumConnReleased: 44919伯爵 NumConnCreated: 9748计数
NumConnDestroyed: 9793计数
NumConnFailedValidation: 70计数
NumConnFree: 161计数
NumConnUsed: -136点数

如何 NumConnFree可以变为161 Maximum Pool Size = 100
{<1}}如何成为-136,否定数字
{<1}} &gt; NumConnUsed 可以

8 个答案:

答案 0 :(得分:9)

连接失败,可能是由于防火墙空闲超时等原因。如果您没有将JDBC驱动程序配置为在失败时重新连接,则除非您打开新连接,否则此错误不会消失。

如果您正在使用数据库连接池( 使用一个,对吗?),那么您可能希望启用它的连接检查功能,例如发出查询以检查是否连接在将其交回应用程序之前正在工作。在Apache commons-dbcp中,这称为validationQuery,通常设置为SELECT 1之类的简单。

由于您使用的是MySQL,因此您应该使用特定于Connector / J的“ping”查询,该查询比实际发出真正的SQL查询重量轻,并将验证查询设置为/* ping */ SELECT 1(ping部分) needs to be exact)。

答案 1 :(得分:8)

这很可能意味着数据库已重新启动或与数据库的网络连接已断开(例如,NAT连接已超时)......并且您的webapp正在尝试使用陈旧的数据库连接。

如果重新启动Web容器后问题仍然存在,则可能会更严重。


您问了以下问题:

How can the NumConnFree become 161 as I have Maximum Pool Size = 100 ?
How can the NumConnUsed become -136, a negative number ?
How can the NumConnDestroyed > NumConnCreated ? 

从表面上看,这些都没有意义。但是,它们可能只是某些使用计数器以非线程安全方式更新的结果。这不一定与您原来的问题有关。

答案 2 :(得分:6)

这是java中的EndOfFileException,当光标起点位于结束点或数据库连接因某些意外异常而关闭时发生。

答案 3 :(得分:5)

虽然我没有确定的解决方案,但似乎是应用服务器和数据库之间存在干扰通信。以下是您可以尝试隔离问题的一些事项:

  • 尝试确定这是mysql问题还是java代码问题。尝试使用与应用服务器相同的主机上的命令行工具连接到mysql,并发出类似的SQL来执行登录。使用一个简单的java代码进行测试,该代码执行select,将其部署到同一个基础架构,查看发生的情况等。另外检查mysql服务器日志,看看是否可以找到任何有用的东西

  • 有两种方式可以关闭空闲连接:通过在app服务器内部运行的连接池代码,或者由mysql本身运行。确保检查双方的配置

  • 检查最近是否有任何网络基础架构配置发生了变化。是否有任何新的防火墙规则干扰了应用服务器&lt; - &gt; mysql连接?是否有任何设置禁止打开TCP连接空闲时间超过X?

  • 尝试使用其他连接池库以消除连接池的可能性

祝你好运

答案 4 :(得分:2)

这可能与防火墙有关。

答案 5 :(得分:1)

我遇到了这个问题,但我无法对MySQL数据库配置进行更改。因此,我确保在我的sql连接器类中,连接始终在它再次启动之前关闭。类似的东西:

public static Connection getConnection() {

    if (DatabaseConnnector.conn == null) {
        initConn();
    } else {
        try {
            DatabaseConnnector.conn.close();          
        } catch (SQLException e) {
            e.printStackTrace();
        }
          initConn();
    }
    return DatabaseConnnector.conn;
}

这解决了这个问题。

答案 6 :(得分:1)

尝试连接和/或从mysql服务器获取一些数据时,在PHPStorm中获得此错误。复选框“单一连接模式”为我修复了问题。 我就把它留在这里。也许这将来会帮助一些烈士。

https://www.jetbrains.com/help/phpstorm/configuring-database-connections.html

答案 7 :(得分:0)

我遇到相同的问题,这是由于锁定时间过多所致。

我们有一个较长的事务A,如果执行它,则其他事务将被锁定,直到事务A完成,所以其他事务总是被我们的mysql工具(pt-kill)杀死