当前位置: 首页 > 后端技术 > Java

Lockwaittimeoutexceeddoned

时间:2023-04-01 14:36:53 Java

后台更新MySQL中的锁表。最近在做一个订单的钉钉审批功能。钉钉审核通过后,订单会更新审核状态,然后添加入库项,更新入库状态://orderApprovalpassed@Transactional(rollbackFor=Exception.class)publicvoidorderPass(){//更新订单审核状态updateOrderAuditStatus(id);//添加存储addPutInStorage(id);//更新订单存储状态updateOrderStorageStatus(id);其中addstorage为远程ERP存储,adddelivery后更新发货状态。因为ERP可能会因为库存不足导致入库失败。但此时审批流程已经结束,无法再次发起审批流程。添加入库失败时,订单审核状态更新正常,添加入库和更新入库状态失败。这里的解决方案是:拆分成两种方式,一种是更新订单审核状态,另一种是添加入库和更新入库状态。添加入库和更新入库状态启动一个事务,即添加一个嵌套的事务REQUIRES_NEW,REQUIRES_NEW表示不管有没有事务都会创建一个新的事务。修改后的代码如下://订单审核通过@Transactional(rollbackFor=Exception.class)publicvoidorderPass(){//更新订单审核状态updateOrderAuditStatus(id);try{//更新出站updatePutInStorage(id);}catch(Exceptione){System.out.println("无法更新存储空间");}}//更新出存储@Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRES_NEW)publicvoidupdatePutInStorage(Longid)throwsException{//添加存储addPutInStorage(id);//更新订单存储状态updateOrderStorageStatus(id);System.out.println("updateoutofstoragesuccessfully");}上面的代码分为更新订单审核状态和更新入库,其中更新入库错误会被trycatch异常捕捉到,不会影响更新订单审核状态。但是添加存储和更新订单存储状态是在同一个事务下,要么同时成功,要么同时失败。上面的问题也解决了。但是运行结果:com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException:Lockwaittimeoutexceeded;尝试重启事务原因分析锁超时,为什么会有锁?主要是这里添加了REQUIRES_NEW。外部事务对表的更新锁定了表的行。外层事务提交前调用内层事务updatePutInStorage,内层事务调用updatePutInStorage。updatePutInStorage需要更新订单的入库状态。此时外层事务锁表,更新订单的入库状态无法更新。更新订单的入库状态等待更新订单的审核状态,REQUIRES_NEW会让更新订单的审核状态等待更新订单的入库状态。互相等待会导致死锁。解决死锁:两个线程使用两个互斥量来保护两个不同的共享资源。当这两个互斥量应用不当时,可能会导致两个线程互相等待对方释放锁。在没有外力作用的情况下,这些线程会一直互相等待,没有办法继续运行下去。在这种情况下,就会发生死锁。上述锁超时的原因是造成死锁的原因之一。所以需要把更新订单审核状态的方法放在最后}catch(Exceptione){System.out.println("更新出站失败");}//更新订单审核状态updateOrderAuditStatus(id);}//更新出站@Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRES_NEW)publicvoidupdatePutInStorage(Longid)throwsException{//添加存储addPutInStorage(id);//更新订单存储状态updateOrderStorageStatus(id);System.out.println("Updateoutboundsuccessfully");}总结添加嵌套事务需要考虑死锁问题。直到所有方法都执行完毕,事务才会提交事务。包含嵌套事务的更新需要按照相同的顺序更新,否则锁可能会互相等待。参考业务中第一次MySQL更新锁表超时(Lockwaittimeoutexceeded;tryrestarttransaction)