MySQLTransactionRollbackException

问题描述

mysql部署1主3从,昨天发现主库有大量报警错误:

Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

; Deadlock found when trying to get lock; try restarting transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

定位根因

MySQLTransactionRollbackException是MySQL 处理并发事务时的典型错误。一般有死锁Deadlock和锁等待超时innodb_lock_wait_timeout两种;

当两个或多个事务相互等待对方持有的锁资源时,MySQL 会主动终止其中一个事务以打破僵局,从而抛出该异常,这一过程由 InnoDB 的死锁检测机制自动完成,无需人工干预。

分析死锁日志,定位冲突点:MySQL 会记录死锁详情到错误日志中,可通过以下命令查看最近一次死锁信息:

sql 复制代码
SHOW ENGINE INNODB STATUS;

在输出的 LATEST DETECTED DEADLOCK 部分,能看到:

  • 参与死锁的事务 ID 和 SQL 语句。
  • 事务持有和等待的锁类型(如 X-lock 排他锁)。
  • 涉及的表和行记录(通过 space idpage no 定位)。
sql 复制代码
            LATEST DETECTED DEADLOCK
------------------------
2025-09-11 17:19:22 0x7ee2dbbdf700
*** (1) TRANSACTION:
TRANSACTION 922499728, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 24349657, OS thread handle 139512913655552, query id 4391620199 10.199.99.99 kms_mpmanage_st_pjab updating
/*id:3b7f6356*//*ip=10.199.99.99*/update srunning
    set report_time = 1757582355865,
      is_del = 0,
      graph_version = null,
      service_item = 'aaaaa',
      build_id = 9652,
      report_version = 2,
      config_version = 'config-202508112023',
      scene_sdk_version = '1.3.20',
      table_sdk_version = '2.4.31'
    where pid = 179529542 and report_time < 1757582355865
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 828 page no 8 n bits 200 index uniq_ip_app_scene_s of table `camp`.`srunning` trx id 922499728 lock_mode X locks rec but not gap waiting
*** (2) TRANSACTION:
TRANSACTION 922499723, ACTIVE 0 sec fetching rows
mysql tables in use 1, locked 1
27 lock struct(s), heap size 3520, 35 row lock(s), undo log entries 12
MySQL thread id 24348682, OS thread handle 139512814368512, query id 4391620202 10.199.99.99 kms_mpmanage_st_pjab updating
/*id:389d6f54*//*ip=10.199.99.99*/update srunning
     SET report_time = 1757582353855, is_del = 1 WHERE ( pid = 179529542 and report_time < 1757582353855 )
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 828 page no 8 n bits 200 index uniq_ip_app_scene_s of table `camp`.`srunning` trx id 922499723 lock_mode X locks rec but not gap
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 828 page no 8 n bits 200 index uniq_ip_app_scene_s of table `camp`.`srunning` trx id 922499723 lock_mode X waiting
*** WE ROLL BACK TRANSACTION (1)

两个update更新同一表死锁是两个事务在该表中以不同顺序获取行锁,形成循环等待。

解决和避免

业务涉及事务的4个表都达到了500W+,且事务内同时查询插入或更新4个表,所以多次死锁

统一事务操作顺序

多个事务更新同一批行时,按相反或不同的顺序执行 UPDATE,是单表死锁的最主要原因。

降低锁粒度或使用合理的索引

使用非主键索引、范围条件(>, <, BETWEEN)等,导致 InnoDB 加锁范围扩大(如间隙锁、临键锁),增加交叉等待概率。

缩小事务范围减少锁持有时间

事务执行时间过长,长时间占用锁资源,提高了与其他事务形成循环等待的可能性。

数据表量级对性能有显著影响

  • 小型表(10 万行以内)SELECT、INSERT、UPDATE基本无瓶颈,操作耗时主要受 SQL 语句写法影响
  • 中型表(10 万~1000 万行):SELECT 无索引的全表扫描开始变慢,有索引但索引设计不合理(如低基数索引)时,性能下降明显,复杂查询(多表关联、子查询)耗时增加,可能出现临时表或文件排序。INSERT :单条插入影响不大,但批量插入可能因索引维护(如 B+ 树分裂)耗时增加。若表有多个索引,写入性能下降更明显(每个索引都需更新)。UPDATE:基于非索引字段的更新需要全表扫描,耗时显著增加。高频更新可能导致行锁 / 表锁竞争,出现等待延迟。
  • 大型表(1000 万~1 亿行):需要分库分表、数据归档等拆分

代码层面捕获异常并重试

死锁是临时性异常,重试通常可解决。在代码中捕获 MySQLTransactionRollbackException,并设置合理的重试机制

锁类型

  • lock_type:锁类型,常见值:
    • RECORD:行级锁(针对具体行记录)。
    • TABLE:表级锁(针对整个表)。
  • lock_mode:锁模式,常见值:
    • S:共享锁(读锁,允许其他事务读,不允许写)。
    • X:排他锁(写锁,禁止其他事务读和写)。
    • GAP:间隙锁(锁定索引间隙,防止插入数据)。
    • Next-Key:临键锁(行锁 + 间隙锁的组合,默认的行锁模式)。

行级排他锁,UPDATE/DELETE/INSERT 时自动加锁,阻止其他事务修改该行。

行级共享锁,SELECT ... FOR SHARE 显式加锁,允许其他事务读,但阻止写。

排他间隙锁,锁定索引间隙,防止其他事务插入数据(如 UPDATE ... WHERE id > 10 可能触发)。

临键锁(默认行锁模式),锁定行及前面的间隙,防止幻读(REPEATABLE READ 隔离级别下默认)。

相关推荐
流星白龙18 小时前
【MySQL高阶】7.MySQL日志
数据库·mysql·adb
流星白龙18 小时前
【MySQL高阶】0.MySQL的安装
数据库·mysql·adb
流星白龙20 小时前
【MySQL高阶】6.MySQL数据目录,日志
android·mysql·adb
流星白龙21 小时前
【MySQL高阶】2.MySQL命令行客户端(2)
android·mysql·adb
流星白龙21 小时前
【MySQL高阶】5.MySQL服务器简介
服务器·mysql·adb
流星白龙21 小时前
【MySQL高阶】9.在一台机器上运行多个MySQL实例
数据库·mysql·adb
流星白龙1 天前
【MySQL高阶】8.MySQL系统库
android·mysql·adb
亚空间仓鼠4 天前
Docker容器化高可用架构部署方案(十七)
adb
AI人工智能+电脑小能手4 天前
【大白话说Java面试题 第80题】【Mysql篇】第10题:MySQL 在什么条件下索引失效?
java·开发语言·mysql·adb·面试
会Tk矩阵群控的小木4 天前
深入解析tk矩阵系统ADB实时投屏与多设备控制实现
运维·线性代数·adb·矩阵·个人开发