https://blog.csdn.net/qq_24948625/article/details/124824624

https://www.nowcoder.com/feed/main/detail/13d0bebb9cf64d58885a73904654f1fc

在同一个class中,方法A调用方法B,调用的是原对象的方法,而不通过代理对象。所以Spring无法切到这次调用,也就无法通过注解保证事务性了。

也就是说,在同一个类中的方法调用,则不会被方法拦截器拦截到,因此事务不会起作用。

1.代码中事务控制的3种方式

编程式事务:就是直接在代码里手动开启事务,手动提交,手动回滚。优点就是可以灵活控制,缺点就是太麻烦了,太多重复的代码了。

声明式事务:就是使用SpringAop配置事务,这种方式大大的简化了编码。需要注意的是切入点表达式一定要写正确。

注解事务:直接在Service层的方法上面加上@Transactional注解,个人比较喜欢用这种方式。

2.事务不回滚的原因

在工作中,看过别人写的代码出现了事务不回滚的现象。当然,事务不回滚的都是采用的声明式事务或者是注解事务;编程式事务都是自己写代码手动回滚的,因此是不会出现不回滚的现象。

再说下 声明式 事务和注解事务回滚的原理:当被切面切中或者是加了注解的方法中抛出了RuntimeException异常时,Spring会进行事务回滚。默认 情况下是 捕获到方法的 RuntimeException 异常 ,也就是说抛出只要属于运行时的异常(即 RuntimeException及其子类 )都能回滚;但当抛出一个不属于运行时异常时,事务是不会回滚的。

下面说说我经常见到的3种事务不回滚的产生原因:

(1)声明式事务配置切入点表达式写错了,没切中Service中的方法

(2)Service方法中,把异常给try catch了,但catch里面只是打印了异常信息,没有手动抛出RuntimeException异常

(3)Service方法中,抛出的异常不属于运行时异常(如IO异常),因为Spring默认情况下是捕获到运行时异常就回滚。

3.无事务a()方法中调用同一个类的有事务b()方法的情况

在Spring管理的项目中,方法B使用了Transactional注解,试图实现事务性。但当同一个class中的方法A调用方法B时,会发现方法B中的异常不再导致回滚,也即事务失效了。

当这个方法被同一个类调用的时候,spring无法将这个方法加到事务管理中。

public class UserService extends BaseServerTest {

    private static final Logger logger = Logger.getLogger(PropagationTest.class);

    @Autowired
    UserMapper userMapper;

    @Test
    public void a() {
        try {
            b();
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = false, rollbackFor = RuntimeException.class)
    public void b() {
        try {
            userMapper.saveNews(new JSONArray());
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }
}