背景

最近在做一个订单的钉钉审批功能,钉钉审批通过之后,订单更新审核状态,然后添加一条付款,并且更新付款状态:

// 订单审批通过
@Transactional(rollbackFor = Exception.class)
public void orderPass() {
// 更新订单审核状态
updateOrderAuditStatus(id);
// 添加入库
addPutInStorage(id);
// 更新订单入库状态
updateOrderStorageStatus(id);
}

其中的添加入库是远程ERP入库,添加出库之后更新出库状态。因为ERP可能因为库存不足,会入库失败。但此时审批流程已经结束,不可能再发起一遍审批流程。当添加入库失败订单审核状态正常更新,添加入库更新入库状态失败。这里的解决方案是:

拆分成两个方法,一个是更新订单审核状态,另一个添加入库和更新入库状态。添加入库和更新入库状态开启一个事务,也就是添加嵌套事务 REQUIRES_NEW,REQUIRES_NEW表示无论是否有事务,都会创建一个新的事务。

修改后的代码如下:

// 订单审批通过
@Transactional(rollbackFor = Exception.class)
public void orderPass() {
// 更新订单审核状态
updateOrderAuditStatus(id);
try {
// 更新出库
updatePutInStorage(id);
} catch (Exception e) {
System.out.println("更新出库失败");
} } // 更新出库
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void updatePutInStorage(Long id) throws Exception{
// 添加入库
addPutInStorage(id);
// 更新订单入库状态
updateOrderStorageStatus(id);
System.out.println("更新出库成功");
}

上面讲代码拆分成更新订单审核状态更新入库,其中更新入库报错会被try catch异常捕获,不会影响到订单审核状态更新。而添加入库更新订单入库状态处于同一个事务下,要么同时成功,要么同时失败。上述问题也解决了。

然而运行结果

com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

原因分析

锁超时了,为什么会有锁呢?主要是这里添加了REQUIRES_NEW

  • 外层事务对表的更新锁住了表的行,外层事务还没有提交,就调用了内层事务updatePutInStorage,内层事务调用了updatePutInStorage
  • updatePutInStorage需要更新订单的入库状态,此时外层事务锁住了该表,所以更新订单的入库状态无法更新。
  • 更新订单的入库状态等待更新订单的审核状态,而REQUIRES_NEW又会让更新订单的审核状态等待更新订单的入库状态。造成相互等待,也就造成死锁

解决方案

死锁:两个线程为了保护两个不同的共享资源而使用了两个互斥锁,那么这两个互斥锁应用不当的时候,可能会造成两个线程都在等待对方释放锁,在没有外力的作用下,这些线程会一直相互等待,就没办法继续运行,这种情况就是发生了死锁。

上面锁超时原因,就是死锁的一种原因。所以需要把更新订单审核状态方法放在最后:

// 订单审批通过
@Transactional(rollbackFor = Exception.class)
public void orderPass() { try {
// 更新出库
updatePutInStorage(id);
} catch (Exception e) {
System.out.println("更新出库失败");
}
// 更新订单审核状态
updateOrderAuditStatus(id); } // 更新出库
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void updatePutInStorage(Long id) throws Exception{
// 添加入库
addPutInStorage(id);
// 更新订单入库状态
updateOrderStorageStatus(id);
System.out.println("更新出库成功");
}

总结

  • 添加嵌套事务需要考虑到死锁的问题。
  • 一个事务只有等全部方法执行完毕之后才会提交事务。
  • 含有嵌套的事务的更新,需要按照相同的顺序更新,不然可能会出现锁相互等待的情况。

参考

业务上第一次遇到MySQL更新锁表超时( Lock wait timeout exceeded; try restarting transaction)

MySQL更新锁表超时 Lock wait timeout exceeded的更多相关文章

  1. Mysql事物锁等待超时(Lock wait timeout exceeded; try restarting transaction)

    一.问题描述 在做查询语句时,MySQL 抛出了这样的异常:锁等待超时 Lock wait timeout exceeded; try restarting transaction,是当前事务在等待其 ...

  2. MySQL事务锁等待超时 Lock wait timeout exceeded; try restarting transaction

    工作中处理定时任务分发消息时出现的问题,在查找并解决问题的时候,将相关的问题博客收集整理,在此记录下,以便之后再遇到相同的问题,方便查阅. 问题场景 问题出现的场景: 在消息队列处理消息时,同一事务内 ...

  3. com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

    本文为博主原创: 以下为在程序运行过程中报的错误, org.springframework.dao.CannotAcquireLockException: ### Error updating dat ...

  4. com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction 问题解决

    有两种设置方法 第一种在mysql的配置文件中加入,然后重启mysql innodb_lock_wait_timeout = 500 第二种直接执行如下命令 set global innodb_loc ...

  5. Mysql错误:ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

    昨晚添加完索引之后, 查询整表的时候抛出Lock wait timeout exceeded; try restarting transaction, 吓死小白的我, 为什么条件查询可以, 整表查不了 ...

  6. Mysql错误: ERROR 1205: Lock wait timeout exceeded解决办法(MySQL锁表、事物锁表的处理方法)

    Java执行一个SQL查询未提交,遇到1205错误. java.lang.Exception: ### Error updating database.  Cause: java.sql.SQLExc ...

  7. mysql异常Lock wait timeout exceeded; try restarting transaction

    mysql中使用update语句更新数据报错: Lock wait timeout exceeded; try restarting transaction. 这是由于你要更新的表的锁在其它线程手里. ...

  8. Lock wait timeout exceeded?代码该优化了

    背景 最近在排查问题时发现,偶尔会发生关于数据库锁超时的现象,会发生像如下的报错信息: Exception in thread "pool-3-thread-1" org.spri ...

  9. MySQL事务锁问题-Lock wait timeout exceeded

    转载:https://cloud.tencent.com/developer/article/1356959 问题现象:   接口响应时间超长,耗时几十秒才返回错误提示,后台日志中出现Lock wai ...

随机推荐

  1. 存储器、I/O组织、微处理器

    重点知识 存储器的内部结构及访问方法 存储器分段以及存储器中的逻辑地址和物理地址 I/O端口组织及编址方式 时序和总线操作以及系统的工作方式和特点. 存储器组织 8086有20根地址线,可寻址的存储器 ...

  2. Java开发学习(五)----bean的生命周期

    一.什么是生命周期 首先理解下什么是生命周期? 从创建到消亡的完整过程,例如人从出生到死亡的整个过程就是一个生命周期. bean生命周期是什么? bean对象从创建到销毁的整体过程. bean生命周期 ...

  3. TypeScript(7)泛型

    泛型 指在定义函数.接口或类的时候,不预先指定具体的类型,而在使用的时候再指定具体类型的一种特性. 引入 下面创建一个函数, 实现功能: 根据指定的数量 count 和数据 value , 创建一个包 ...

  4. VisionPro · C# · 加载与保存视觉工具包

    当项目程序被启动或更换程序产品型号时,我们需要提前加载对应的VisionPro的程序VPP文件,以提高程序调用效率. 加载代码: 1 using System; 2 using System.Wind ...

  5. Web思维导图实现的技术点分析(附完整源码)

    简介 思维导图是一种常见的表达发散性思维的有效工具,市面上有非常多的工具可以用来画思维导图,有免费的也有收费的,此外也有一些可以用来帮助快速实现的JavaScript类库,如:jsMind.KityM ...

  6. 摸鱼人常备5个Python迷你项目,玩一整天不是问题(附源码)

    大家好鸭,我是小熊猫 在使用Python的过程中,我最喜欢的就是Python的各种第三方库,能够完成很多操作. 下面就给大家介绍5个通过Python构建的项目,以此来学习Python编程. 一.石头剪 ...

  7. Python爬取全球是最大的电影数据库网站IMDb数据

    在使用 Python 开发爬虫的过程中,requests 和 BeautifulSoup4(别名bs4) 应用的比较广泛,requests主要用于模拟浏览器的客户端请求,以获取服务器端响应,接收到的响 ...

  8. C# / VB.NET 将Html转为Word

    本文分享以C#程序代码为例,实现将Html文件转换Word文档的方法(附VB.NET代码).在实际转换场景中可参考本文的方法,转换前,请按照如下方法引用Word API的dll文件到Visual St ...

  9. 关于vm虚拟机的问题

    这几天搞虚拟机搞的头疼,真是一步一个坑,总结以下几个问题: 安装不了或用户不接受协议:原因应该是你之前装过vm,没有彻底清理,和本次安装形成了对抗,所以我们需要安装WindowsInstallerCl ...

  10. 《ASP.NET Core 6框架揭秘》样章[200页/5章]

    作为<ASP.NET Core 3 框架揭秘>的升级版,<ASP.NET Core 6框架揭秘>不仅针对ASP.NET Core 6的新特性进行了修订,并添加了若干原来没有的内 ...