Spring JPA+MySQL提交阶段触发死锁但数据库error_log无记录问题
提交阶段触发死锁但MySQL无死锁日志问题排查结果
首先可以明确,JPA不会在应用侧自行触发这类死锁异常。com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException是MySQL官方JDBC驱动专属的异常类,只有当驱动收到MySQL服务端返回的错误码1213(死锁错误)时才会抛出,不存在应用层凭空生成的可能。
为什么异常抛在ConnectionImpl.commit的return行
你看到堆栈对应行只有return;是源码版本不匹配导致的行号偏移:
- 你本地查看的mysql-connector-java源码版本,和线上实际运行的版本不一致,或者驱动编译时的行号调试信息存在偏差
- 该行
return之前的逻辑已经完成了COMMIT命令的发送、服务端响应的读取解析,异常是在解析到服务端返回的死锁错误时抛出的,和return语句本身无关
为什么MySQL没有记录死锁日志
你开启的innodb_print_all_deadlocks参数仅会记录InnoDB行级锁产生的死锁,以下场景的死锁不会被该参数记录:
- MDL元数据锁死锁:如果你的事务执行过程中,有其他会话对涉及的表执行DDL、锁表等操作,触发MDL锁等待形成死锁,这类死锁属于MySQL Server层的锁冲突,不会被InnoDB日志记录,只会输出到MySQL的全局error log中
- 临时表锁死锁:如果你的事务中操作了临时表,临时表是会话级别的,这类死锁不会被InnoDB计入死锁日志
- 提交阶段瞬时死锁:死锁检测触发时,其中一方事务已经进入提交终态,InnoDB的日志生成逻辑会跳过这类无活跃冲突方的死锁场景,避免生成无效日志
常规解决方案
- 排查对应事务中的所有SQL,确认是否有操作临时表、或者在事务中触发MDL锁的语句
- 可通过开启MySQL的MDL锁监控、或者在异常时间点查询
performance_schema.data_locks等系统表定位锁冲突来源 - 死锁属于瞬时异常,直接给对应
@Transactional方法增加3次以内的重试机制即可解决绝大多数偶发死锁问题
内容的提问来源于stack exchange,提问作者AndD
相关产品推荐
相关产品推荐

