共计 1710 个字符,预计需要花费 5 分钟才能阅读完成。
@Transactional 导致报错 Lock wait timeout exceeded; try restarting transaction
前言
最近线上我的项目报
Lock wait timeout exceeded; try restarting transaction
排查
-
百度 Lock wait timeout exceeded; try restarting transaction
大略意思,就是 mysql 当中有死锁。须要排查
- 查看以后过程 show full processlist;
-
查看 mysql 锁表 select * from information_schema.innodb_trx;
此处后果须要在意的是 trx_state,trx_mysql_thread_id 两个字段。
- 以上后果,没有 trx_state = LOCK_WAIT 的后果,就证实 mysql 内没有死锁。
- 迷茫了,不晓得该咋解决了。
- 监控 mysql 吧,不停的刷 show full processlist;
- 无心中发现一条 sql 查问语句,不停的再执行。去零碎内查看此 sql 语句。
- 发现零碎内一个 service 办法下面,应用了 @Transactional
- 那么问题来了,应用了 @Transactional 为什么会报 Lock wait timeout exceeded; try restarting transaction
- 猜测是否有一个工作,再执行此办法,其余的工作也来执行此办法。
测试猜测
-
写了两个办法,外面同时有 select,update
@Override @Transactional public Person getPerson() {System.out.println("getPerson1 拜访程序启动:===========》" + System.currentTimeMillis()); Person person = getById(1); System.out.println(person.getName()); person.setName("测试"+System.currentTimeMillis()); updateById(person); try {Thread.sleep(100000); } catch (InterruptedException e) {e.printStackTrace(); } System.out.println("getPerson1 拜访程序完结:===========》" + System.currentTimeMillis()); return person; } @Override @Transactional public Person getPerson2() {System.out.println("getPerson2 拜访程序启动:===========》" + System.currentTimeMillis()); Person person = getById(2); System.out.println(person.getName()); person.setName("测试"+System.currentTimeMillis()); updateById(person); try {Thread.sleep(100000); } catch (InterruptedException e) {e.printStackTrace(); } System.out.println("拜访程序完结:===========》" + System.currentTimeMillis()); return person; }
-
写两个单元测试,别离同时申请
@Test void demo2() {personService.getPerson(); } @Test void demo3() {personService.getPerson2(); }
- 后果
- getById() 都是 1 的时候,复现了
- getById() 不同的时候,没有复现
![1642411180281]
![1642411186155]
论断
- @Transactional 是行级锁
- mysql 期待事务锁 innodb_lock_wait_timeout 默认 50s
- 应用事务的状况下,尽量简化 service 代码。
正文完