前言
服务报错:
Lock wait timeout exceeded; try restarting transaction
排查
字面意思 锁等待超时了,尝试重启事务。
既然是数据库死锁,着手排查数据库死锁信息
查看最近死锁的日志
show engine innodb status
在打印出来的信息中找到“LATEST DETECTED DEADLOCK”一节内容
分析其中的内容,我们就可以知道最近导致死锁的事务有哪些
通过sql匹配到具体的代码块发现,该方法使用了事务
@Transactional(rollbackFor = Exception.class)
,但该方法时单表更新,无需事务
因更新前有大量的查询操作导致事务时间超长
解决
去除只读事务和单表事务,问题解决
复盘
通过日志信息得出数据库死锁,再排查到相关业务代码,因事务中含有大量耗时查询导致事务超时,无法更新导致死锁
尽量减少@Transactiona注解使用,如需使用尽量事务粒度细化可使用
@Autowired
private TransactionTemplate transactionTemplate;
总结
少用@Transactional及只读事务
事务中避免一次性处理太多数据
如需使用事务尽量细化
异步处理非事务代码
扩展
死锁信息查看
1、查看正在进行中的事务 SELECT * FROM information_schema.INNODB_TRX
2、查看正在锁的事务 SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
3、查看等待锁的事务 SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
4、查询是否锁表 SHOW OPEN TABLES where In_use > 0;
5、查看最近死锁的日志 SHOW ENGINE INNODB STATUS
解除死锁
解除死锁
查看当前正在进行中的进程
show processlist
也可以使用 SELECT * FROM information_schema.INNODB_TRX;
这两个命令找出来的进程id 是同一个。 杀掉进程对应的进程
kill id
@Transactional(readOnly = true)
@Transactional(readOnly = true)注解,申明为只读事务。
多条查询下要使用该注解,能够防止多次查询到的数据不一致(维持可重复读)。
在将事务设置成只读后,当前只读事务就不能进行写的操作,否则报错。如下
Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed;
事务粒度细化
新加Service方法
@Servcie
publicclass ServiceA {
@Autowired
prvate ServiceB serviceB;
public void save(User user) {
queryData1();
queryData2();
serviceB.doSave(user);
}
}
@Servcie
publicclass ServiceB {
@Transactional(rollbackFor=Exception.class)
public void doSave(User user) {
addData1();
updateData2();
}
}
在该Service类中注入自己
@Servcie
publicclass ServiceA {
@Autowired
prvate ServiceA serviceA;
public void save(User user) {
queryData1();
queryData2();
serviceA.doSave(user);
}
@Transactional(rollbackFor=Exception.class)
public void doSave(User user) {
addData1();
updateData2();
}
}
重要的东西全部都在半径三米以内
转载请注明:Lock wait timeout exceeded; try restarting transaction解决 | 胖虎的工具箱-编程导航