【问题标题】:Communications link failure to MySQL during long LOCK TABLES在长 LOCK TABLES 期间与 MySQL 的通信链接失败
【发布时间】:2013-07-10 15:44:38
【问题描述】:

我遇到了一些奇怪的行为。我有一个 Java 程序,它使用准备好的语句和批量插入将数据永久写入 MySQL 表。如果某个其他进程在同一个表上发出LOCK TABLES t WRITE,并在此后不久(几分钟后)释放它,Java 程序将按预期继续。但是,当锁定持续较长时间(超过 30 分钟)时,Java 程序会失去连接并且不会继续。 2 小时后,它会因 通信链接故障 而失败。表锁期间挂起的insert语句在锁被释放后执行,但之后连接就消失了。

以下是详细信息:

  • 它发生在 MySQL 5.0.51a 和 5.1.66 上
  • 我正在使用最新的 JDBC 驱动程序 mysql-connector-5.1.25-bin.jar
  • wait_timeout 设置为 28800(8 小时)
  • 通信链路故障的堆栈跟踪和 Java 程序如下所示

有人知道这里发生了什么吗?我需要设置/增加任何超时吗?


两小时后抛出的异常:

Exception in thread "main" java.sql.BatchUpdateException: Communications link failure

The last packet successfully received from the server was 7.260.436 milliseconds ago.  The last packet sent successfully to the server was 7.210.431 milliseconds ago.
    at com.mysql.jdbc.PreparedStatement.executeBatchedInserts(PreparedStatement.java:1836)
    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1456)
    at com.mysql.jdbc.CallableStatement.executeBatch(CallableStatement.java:2499)
    at main.LockTest.main(LockTest.java:26)
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 7.260.436 milliseconds ago.  The last packet sent successfully to the server was 7.210.431 milliseconds ago.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
    at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1121)
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3670)
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3559)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4110)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2570)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2731)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2815)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2375)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2359)
    at com.mysql.jdbc.PreparedStatement.executeBatchedInserts(PreparedStatement.java:1792)
    ... 3 more
Caused by: java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:114)
    at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:161)
    at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:189)
    at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3116)
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3570)
    ... 13 more

完整的 Java 程序:

package main;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

public class LockTest {

    private static final String CONNECTION_PATTERN = "jdbc:mysql://%s/?user=%s&password=%s"
            + "&autoReconnect=true&rewriteBatchedStatements=true&characterEncoding=utf8";
    private static final String QUERY = "INSERT INTO test.lock_test (random_text) VALUES (?)";

    public static void main(String[] args) throws SQLException, InterruptedException {
        Connection con = DriverManager.getConnection(String.format(CONNECTION_PATTERN, "host", "user", "pw"));
        PreparedStatement ps = con.prepareCall(QUERY);
        int i = 0;
        while (true) {
            i++;
            ps.setString(1, Long.toString(System.currentTimeMillis()));
            ps.addBatch();
            if (i % 10 == 0) {
                ps.executeBatch();
                System.out.println(new Date() + ": inserting 10 rows");
            }
            Thread.sleep(5000);
        }
    }
}

【问题讨论】:

    标签: mysql table-locking


    【解决方案1】:

    我只是搜索相同的问题。我想我的回答可以帮到你。

    1. 查看您的例外情况

    从服务器成功接收到的最后一个数据包是 7.260.436 毫秒前。

    这显然意味着 7.260.436 毫秒

    2.如果你的应用程序因为wait_timeout太小而抛出异常。异常显示如下:

    com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:从服务器成功接收到的最后一个数据包是 46,208,149 毫秒前。最后一个成功发送到服务器的数据包是在 46,208,150 毫秒前。比服务器配置的“wait_timeout”值长。您应该考虑在应用程序中使用之前使连接有效性过期和/或测试,增加客户端超时的服务器配置值,或使用连接器/J 连接属性“autoReconnect=true”来避免此问题。 ; SQL [];从服务器成功接收到的最后一个数据包是 46,208,149 毫秒前。 最后一个成功发送到服务器的数据包是在 46,208,150 毫秒前。 比服务器配置的“wait_timeout”值长。 在您的应用程序中使用之前,您应该考虑过期和/或测试连接有效性, 增加客户端超时的服务器配置值, 或使用 Connector/J 连接属性 'autoReconnect=true' 来避免此问题。

    这意味着 46,208,150 毫秒前 > wait_timeout

    1. 回答!!!

    注意下面的关键字“Communications link failure”,这主要是MySQl变量:net_write_timeout or net_read_timeout

    com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:通信链路故障

    net_write_timeout和net_read_timeout的默认值很小,可以执行

     mysql> show variables like '%timeout%';
    来查找结果。

    【讨论】:

      【解决方案2】:

      终于,我找到了真正的原因。 MySQL 的wait_timeout 与问题无关——只要语句在运行(不管运行多长时间),数据库会话就不会处于SLEEP 状态,因此 MySQL 永远不会关闭会话。

      原因似乎是Linux操作系统(Debian 6或7),闲置2小时后关闭tcp连接(具体机制我不知道,也许有人可以详细说明一下?)。

      为了避免上述超时,需要发送更频繁的 tcp keep alive 数据包。为此,必须减少 /proc/sys/net/ipv4/tcp_keepalive_time(我将其从 7,200 减少到 60)。 cat 60 > /proc/sys/net/ipv4/tcp_keepalive_time 暂时这样做;要在系统重启后保留它,必须在/etc/sysctl.conf 中设置net.ipv4.tcp_keepalive_time=60

      【讨论】:

      • 我无法使用vi 更改我的保持活动文件tcp_keepalive_time" E667: Fsynch has failed 的内容。我必须这样做:root@sd-53310:/home/ocatelin# echo 60 | sudo dd of=/proc/sys/net/ipv4/tcp_keepalive_time 0+1 enregistrements lus 0+1 enregistrements écrits 3 octets (3 B) copiés, 2,4948e-05 s, 120 kB/s root@sd-53310:/home/ocatelin# cat /proc/sys/net/ipv4/tcp_keepalive_time 60
      猜你喜欢
      • 1970-01-01
      • 2012-12-21
      • 2021-01-12
      • 2015-01-27
      • 2014-06-09
      • 2016-09-25
      • 2013-02-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多