记录工做遇到的死锁问题(Lock wait timeout exceeded; try restarting transaction)

1.问题背景

刚来新公司不久,对业务还不太熟悉,因此领导先安排我维护原有系统。大概介绍下项目背景,项目分为核心业务部分在项目A中,与第三方交互的业务在项目B中,前端发起请求调用A项目接口,并在A项目中调用B项目接口,并在B项目中调用第三方获取数据(原有系统这样设计的)。前端

获取到第三方数据后判断数据库中是否有该记录(有惟一键),若有则执行更新操做,没有则新增。而且若是第三方认为该数据已失效,须要从数据库中删除(逻辑删除),并返回第三方删除成功回调,后续便不会再查到已失效的数据。sql

对应流程图以下数据库

在代码处理中对整个过程加事务@Transactional注解,即在对数据进行删除(逻辑删除,实际执行update语句)时会根据惟一索引对该行加锁。在生成环境B项目频繁出现Lock wait timeout exceeded; try restarting transaction 异常,经排查定位到该功能代码,排查代码发现该功能有以下代码tomcat

有经验的同窗应该已经看出问题所在,这里将全局异常捕获,记录错误日志,但问题就出在catch这里,因为异常被catch吞噬,@Transactional没法拿到异常,因此不会执行rollback回滚,致使一直占用数据库行锁。(这里的异常是调用第三方接口失败,因为调用太频繁,第三方接口崩溃,这里后续也作了并发控制) 因此后续事务在执行更新该行记录时因为得不到锁而等待失败,就报了Lock wait timeout exceeded; try restarting transaction 异常。服务器

  

2.问题影响

因为该接口是在核心项目A中有客户端发起调用,并在A项目中调用B项目,因为B项目死锁没法返回结果,致使A项目前端大量请求阻塞,因为tomcat支持的请求线程数有限,该问题直接致使A服务宕机。影响较为严重。并发

 

3.如何解决

下面说下该问题解决思路,因为A项目宕机,在服务器日志中能够看到大量上述异常信息,Lock wait说明出现了锁问题。线程

  a.使用 SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;查看当前事务,使用SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;查看当前锁定的事务,使用SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;查看当前等锁的事务。使用以上三个sql基本能定位到代码所在位置。设计

  b.定位到代码后,就要看具体的代码问题了,致使异常没有回滚的缘由不少。这里说一个注意事项,使用@Transactional注解,默认只会对RuntimeException进行回滚,而对IOException和SQLException不会触发回滚。若是要对两个非运行时异常进行回滚,须要在@Transactional中加入@Transactional( rollbackForClassName = {"IOException","SQLException"})或对全局异常Exception作回滚,配置为@Transactional(rollbackFor = Exception.class)。又或者捕获IOException后手动抛出一个RuntimeExceptionrest

  

总结

  以上为博主在实际工做中遇到的问题,这里记录一下方便之后遇到相似问题能够快速定位并解决问题。也但愿能对你们有帮助。日志

相关文章
相关标签/搜索