springboot 事务手动回滚_SpringBoot事务注解@Transactional 事物回滚、手动回滚事物

本文介绍了SpringBoot中如何处理事务回滚问题,包括默认的异常回滚规则和手动回滚事务的方法。强调了在Service层捕获异常并重新抛出以确保事务回滚的重要性,并提供了使用`@Transactional(rollbackFor=Exception.class)`配合`TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()`来实现手动回滚的示例。
摘要由CSDN通过智能技术生成

处理springboot 下提交事务异常,数据库没有回滚的问题。

spring的文档中说道,spring声明式事务管理默认对非检查型异常和运行时异常进行事务回滚,而对检查型异常则不进行回滚操作。

什么是检查型异常什么又是非检查型异常?

最简单的判断点有两个:

1.继承自runtimeexception或error的是非检查型异常,而继承自exception的则是检查型异常(当然,runtimeexception本身也是exception的子类)。

2.对非检查型类异常可以不用捕获,而检查型异常则必须用try语句块进行处理或者把异常交给上级方法处理总之就是必须写代码处理它。所以必须在service捕获异常,然后再次抛出,这样事务方才起效。

结论:

在spring的事务管理环境下,使用unckecked

exception可以极大地简化异常的处理,只需要在事务层声明可能抛出的异常(这里的异常可以是自定义的unckecked

exception体系),在所有的中间层都只是需要简单throws即可,不需要捕捉和处理,直接到最高层,比如UI层再进行异常的捕捉和处理。

默认规则:

1 让checked例外也回滚: @Transactional(rollbackFor=Exception.class),一般只需添加这个即可

2 让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)

3 不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED),或者不添加

注意:如果异常被try{}catch{}了,事务就不回滚了,如果想让事务回滚必须再往外抛try{}catch{throw Exception}。因为一旦你try{}catch{}了。系统会认为你已经手动处理了异常,就不会进行回滚操作。

示例:

1 @Override2 @Transactional(rollbackFor = Exception.class)3 public Integer submitOrder(FlashbuyOrder flashbuyOrder, ListitemList)4 throwsException5 {6

7 return null;8

9 }

示例

spring 事务控制 设置手动回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

1 //假设这是一个service类的片段

2

3 try{4 //出现异常

5 } catch(Exception e) {6 e.printStackTrace();7 //设置手动回滚

8 TransactionAspectSupport.currentTransactionStatus()9 .setRollbackOnly();10 }11 //此时return语句能够执行

12 return xxx;

View Code

如上:

当我们需要在事务控制的service层类中使用try catch 去捕获异常后,就会使事务控制失效,因为该类的异常并没有抛出,就不是触发事务管理机制。怎样才能即使用try catch去捕获异常,而又让出现异常后spring回滚呢,这里就要用到

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

完美解决问题。并且能够使该方法执行完。

这个需要注意两点:

1. 方法上要加上    @Transactional(rollbackFor = Exception.class)   再配合TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 才可以,

否则会报错  NoTransactionException: No transaction aspect-managed TransactionStatus in scope

at

@Transactional(propagation =Propagation.REQUIRES_NEW,

rollbackFor= Exception.class, isolation =Isolation.REPEATABLE_READ)public void testInsert(int index) throwsException {

OrderDO orderDO= newOrderDO();

orderDO.setThirdOrderId("1000");int rowCount = this.orderMapper.insertOrder(orderDO);if (index == 1) {throw new RuntimeException("wrong");

}if (index == 2) {throw new Exception("wrong");

}if (index == 3) {

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

}

}

View Code

2.  Spring Transactional一直是RD的事务神器,但是如果用不好,反会伤了自己。下面总结@Transactional经常遇到的几个场景:

@Transactional 加于private方法, 无效

@Transactional 加于未加入接口的public方法, 再通过普通接口方法调用, 无效

@Transactional 加于接口方法, 无论下面调用的是private或public方法, 都有效

@Transactional 加于接口方法后, 被本类普通接口方法直接调用, 无效

@Transactional 加于接口方法后, 被本类普通接口方法通过接口调用, 有效

@Transactional 加于接口方法后, 被它类的接口方法调用, 有效

@Transactional 加于接口方法后, 被它类的私有方法调用后, 有效

View Code

Transactional是否生效, 仅取决于是否加载于接口方法, 并且是否通过接口方法调用(而不是本类调用)。

ProductService.java/**********************************************************************/

public interfaceProductService{

Integer getPrice(ProductInfo p);

Integer compute(ProductInfo p);

}/**********************************************************************/ProductServiceImpl.java/**********************************************************************/@Servicepublic class ProductServiceImpl implementsProductService{

@AutowiredprivateProductService productService;publicInteger getPrice(ProductInfo p){

productService.compute(p);

}

@Transactional(rollbackFor= Exception.class)publicInteger compute(ProductInfo p){try{

...

}catch(Exception e){

e.printStackTrace();

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return 0;

}

}

}

是可以的,因为是通过接口调用了

View Code

ProductService.java/**********************************************************************/

public interfaceProductService{

Integer getPrice(ProductInfo p);

}public interfaceMyService{

Integer compute(ProductInfo p);

}/**********************************************************************/ProductServiceImpl.java/**********************************************************************/@Servicepublic class ProductServiceImpl implementsProductService{

@AutowiredprivateMyService myService ;publicInteger getPrice(ProductInfo p){

myService.compute(p);

}

}

@Servicepublic class MyServiceImpl implementsMyService{

@Transactional(rollbackFor= Exception.class)publicInteger compute(ProductInfo p){try{

...

}catch(Exception e){

e.printStackTrace();

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return 0;

}

}

}

放在两个接口类里面,然后通过接口方法调用,是可以生效的

View Code

3.在web项目中,很多时候要用到@Transactional 注解方法或者类进行事务处理,自动事务提交有时候就会有问题,这个时候就要用到手动进行事务提交 ,在try catch 异常抛出里面手动回滚事务处理TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

使用Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint(); 设置回滚点,

使用TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);回滚到savePoint。

转自:

https://blog.csdn.net/zhuchunyan_aijia/article/details/80191534

https://blog.csdn.net/xuhaogang3/article/details/82190026

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值