事务失效问题
如果只对其中的一段代码添加事务,比方只对其中的**this.save(orders);**一行添加事务
想实现的话有两种方案:
- 使用Spring的编程式事务,这种方式控制粒度更精准,但是缺点是代码耦合度高,需要自己写代码处理事务
- 将需要控制事务的那段代码单独提到一个方法中去,然后仅仅对新抽取的方法控制事务
1 2 3 4 5 6 7 8 9 10 11 12
| @Override public PlaceOrderResDTO placeOrder(PlaceOrderReqDTO placeOrderReqDTO) { this.saveOrders(orders); }
@Transactional public void saveOrders(Orders orders){ this.save(orders); }
|
上面的方法可以很好的解决长事务的问题,但是它也引入了一个新的问题,那就是事务失效
1 2 3 4 5 6 7
| @Transactional public void saveOrders(Orders orders){ this.save(orders); int i = 1 / 0; }
|
解决方案
运行上面的代码,会发现事务不再自动回滚,原因很简单:那就是这个方法的调用者是原始对象,不是代理对象
而原始对象是没有事务控制能力的,那解决方案就是将调用者再想办法还原为代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Autowired private IOrdersCreateService owner;
@Override public PlaceOrderResDTO placeOrder(PlaceOrderReqDTO placeOrderReqDTO) { owner.saveOrders(orders); }
@Transactional public void saveOrders(Orders orders){ this.save(orders); }
|
接口中也需要对应的暴露新增的方法
1 2 3 4 5 6
|
void saveOrders(Orders orders);
|
重新测试,事务问题得到解决
总结
事务失效的情况有哪些?
- 非事务方法内部调用事务方法
- 事务方法没有使用public修饰
- 事务方法的异常在方法内被捕获处理
- 事务方法抛出的异常与rollbackFor属性指定的异常不匹配
- 事务方法配置的事务传播行为有误
① 非事务方法内部调用事务方法
在下面方法中,insertOrderAndReduceStock()方法使用的是原始对象调用的,而不是代理对象调用的
而事务管理功能是代理对象负责的,因此事务失效!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Service public class OrderService { public void createOrder(){ insertOrderAndReduceStock(); } @Transactional public void insertOrderAndReduceStock(){ insertOrder(); reduceStock(); } }
|
② 事务方法没有使用public修饰
Spring的声明式事务是基于AOP方式结合动态代理来实现的,在其内部有一个类
AbstractFallbackTransactionAttributeSource会检查方法是否使用public修饰,如果不是,则不能进行功能增强
在下面方法中,createOrder()方法没有使用public修饰,因此无法进行事务增强,事务失效!
1 2 3 4 5 6 7 8 9 10 11 12
| @Service public class OrderService {
@Transactional private void createOrder(){ insertOrder(); reduceStock(); } }
|
③ 事务方法的异常在方法内被捕获处理
在下面方法中,createOrder方法执行过程中即便出现了异常也不会向外抛出
而Spring的事务管理就是要感知业务方法的异常,当捕获到异常后才会回滚事务
现在事务被捕获,就会导致Spring无法感知事务异常,自然不会回滚,事务就失效了!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Service public class OrderService { @Transactional private void createOrder(){ try { insertOrder(); reduceStock(); } catch (Exception e) { } } }
|
④ 事务方法抛出的异常与rollbackFor属性指定的异常不匹配
Spring的@Transactional使用rollbackFor属性指定当前事务管理器感知的异常类型(默认为RuntimeException)
下面方法createOrder方法抛出了一个IOException,不会被Spring捕获,事务就失效了!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Service public class OrderService {
@Transactional(rollbackFor = RuntimeException.class) public void createOrder() throws IOException { try { insertOrder(); reduceStock(); } catch (Exception e) { throw new IOException(); } } }
|
⑤ 事务方法配置的事务传播行为有误
下面方法reduceStock方法配置了事务传播行为Propagation.REQUIRES_NEW,他代表当前方法会开启一个新事物
也就是与createOrder和insertOrder不在同一个事物中了,因此事务失效!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @Service public class OrderService1 {
@Autowired private OrderService2 orderService2;
@Transactional public void createOrder() { orderService2.insertOrder(); orderService2.reduceStock(); }
}
@Service public class OrderService2 {
@Transactional public void insertOrder() { }
@Transactional(propagation = Propagation.REQUIRES_NEW) public void reduceStock() { } }
|