JPA事务控制与外键死锁
问题背景
在做app作业一的第二部分时,遇到了问题(自以为是问题,没想到老师是故意让我们发现这是个bug)。
| 1 | flowchart LR; | 
如图,在电子书服务系统E-Book中,我们进行订单创建,一个订单order中包含多个订单项orderItem。
现在我们要对OrderService::createOrder,OrderDao::saveOne和OrderItemDao::saveList进行事务传播控制,分别简称三部分为A,B,C。
若A和B设置为REQUIRED,而C设置为REQUIRES_NEW,则会出现死锁问题。
源代码大致如下。
| 1 | // OrderServiceImpl.java | 
执行结果为死锁。
原因分析
在B执行后,由于与A处在同一事务一里,则事务一拿到了order表中新插入行的锁,不管事务隔离属性如何设置,其他事务均不可进行写操作。而在随后的C流程中,写入orderItems的时候,order_item表中有order的外键,于是他在给order_item新插入的数据上锁之外,也要在order表中对外键所指向的数据加锁。
然而C是拿不到的,因为B已经拿到了。
于是此时,C等待B放锁,但是同时,B又等待C结束返回,从而形成了死锁。
解决方法
该问题说明,并不是所有业务使用REQUIRES_NEW传播都可以,在此场景下,都使用默认的REQUIRED传播属性即可。
JPA事务控制与外键死锁