You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL多连接事务锁异常:connB绕过connA行锁提交更新

MySQL SELECT ... FOR UPDATE 行锁未阻塞跨连接更新的问题排查与解决

问题核心

InnoDB表中,connA通过SELECT ... FOR UPDATE锁定目标行后,connB的UPDATE操作未按预期被阻塞,反而直接执行成功;命令行测试锁机制正常,但NodeJS/Python代码中复现该问题,同时伴随连接关闭错误。

可能原因分析

  1. MySQL连接超时自动断开
    MySQL的wait_timeout或interactive_timeout参数设置过小,当connA持有锁但长时间无后续操作时,MySQL会主动断开该连接,行锁随之释放,导致connB的UPDATE可以直接执行。实际输出中的got packets out of order警告,正是连接被MySQL关闭后客户端仍尝试操作的典型表现。

  2. 客户端驱动超时设置
    部分数据库驱动(如mysql2/promise、Python的pymysql)默认带有连接超时配置,若超时时间短于事务持有时间,客户端会主动关闭连接,同样导致锁提前释放。

解决方案

1. 调整MySQL服务器超时参数

  • 查看当前超时设置:
    SHOW VARIABLES LIKE '%timeout%';
    
    重点关注wait_timeout和interactive_timeout,若值小于事务持有时间(如10秒以内),就会触发问题。
  • 修改为合适时长(例如300秒):
    SET GLOBAL wait_timeout = 300;
    SET GLOBAL interactive_timeout = 300;
    
    若要持久化配置,需在my.cnf(或my.ini)中添加:
    [mysqld]
    wait_timeout = 300
    interactive_timeout = 300
    
    修改后重启MySQL服务生效。

2. 客户端保持连接活跃

在事务持有期间,定期向MySQL发送心跳查询,避免连接因无操作被断开。例如修改connA的代码,将定时器替换为异步等待并插入心跳:

// 替换原setTimeout部分
console.log("A: Holding transaction (sleeping 15s)");
for (let i = 0; i < 15; i++) {
  await sleep(1000);
  // 发送心跳维持连接
  await connA.query("SELECT 1");
}
console.log("A: Rolling back transaction");
await connA.rollback();
await connA.end();

3. 检查客户端驱动超时配置

确保客户端连接参数中没有设置过短的超时时间。例如mysql2/promise的连接配置中,调整超时参数大于事务持有时间:

let db_details = {
  host: 'localhost',
  user: 'root',
  password: 'password',
  database: 'dbname',
  timeout: 300000, // 设置为300秒
  connectTimeout: 10000 // 连接超时保持合理值即可
}

验证方法

调整参数后重新运行测试代码,观察connB的UPDATE操作是否会被阻塞,直到connA执行回滚后才继续执行;同时检查是否再出现连接关闭的错误提示。

内容的提问来源于stack exchange,提问作者jmc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 09:37:38