Lock wait timeout exceeded; try restarting transaction解决

2年前 (2022) 程序员胖胖胖虎阿
234 0 0

前言

服务报错:

Lock wait timeout exceeded; try restarting transaction

Lock wait timeout exceeded; try restarting transaction解决

排查

字面意思 锁等待超时了,尝试重启事务。
既然是数据库死锁,着手排查数据库死锁信息
查看最近死锁的日志

show engine innodb status
Lock wait timeout exceeded; try restarting transaction解决

在打印出来的信息中找到“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();
    }
 }

重要的东西全部都在半径三米以内

相关文章

暂无评论

暂无评论...