MySQL 更新数据超时失败
问题现象
今天操作线上数据时,想要更新一条数据,结果页面上转了很久,最终http请求超时报错。
查看了后端的应用日志,发现如下信息:
[2024-05-27 10:29:29.294] ERROR c.t.h.e.ExceptionHandlers line:129 -exception for system:
org.springframework.dao.CannotAcquireLockException:
### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
### The error may exist in class path resource [mapper/PackagePOMapper.xml]
### The error may involve cn.tongdun.hera.mapper.PackagePOMapper.updateByPrimaryKeySelective-Inline
### The error occurred while setting parameters
### SQL: update `package` SET tag = ?, package_type = ?, remark = ?, last_updated_by = ? where id = ?
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
; ]; Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:263)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:88)
关键信息一眼就找到: Lock wait timeout exceeded; try restarting transaction
mysql 锁等待超时,是不是有事务还未提交事务就异常中断了?导致其他事务无法获取到修改的锁?
尝试了下新增,新增是没有问题的。
排查分析
使用具有权限的用户登录mysql,执行:show engine innodb status;
查看当前InnoDB 状态,拉到中间,发现返回的信息里有这么一段。
—TRANSACTION 61073962, ACTIVE 6591 sec
2 lock struct(s), heap size 8400, 59 row lock(s), undo log entries 6
MySQL thread id 51644855, OS thread handle 140342299920128, query id 775065555 192.168.10.135 ares
—TRANSACTION 61073883, ACTIVE 8953 sec
3 lock struct(s), heap size 3520, 59 row lock(s), undo log entries 33
MySQL thread id 51637360, OS thread handle 140341246162688, query id 774880224 192.168.10.135 ares
—TRANSACTION 61071129, ACTIVE 11974 sec
3 lock struct(s), heap size 3520, 59 row lock(s), undo log entries 22
MySQL thread id 51630799, OS thread handle 140342452467456, query id 774757507 192.168.10.135 ares
果然有3个事务,已经分别运行了6591 秒、8953秒、11974秒。
至于这三个事务为什么会长时间运行,感觉是业务代码写得不够严禁,并发操作回滚逻辑不严谨。
解决方法
1)查看事务详情,执行:SELECT * FROM INFORMATION_SCHEMA.innodb_trx ORDER BY trx_started;
2)找到需要杀掉的事务线程ID,具体就是查询记录中的 trx_mysql_thread_id 字段值,比如此处找到是555946。
3)执行 kill 555946; 杀死线程。
其他辅助方法:
查看锁情况:SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
查看锁等待情况:SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;