Spring事务传播中嵌套调用实现方法详细介绍

 更新时间:2022年11月08日 17:06:35   作者:宏远十一冠王  
Spring事务的本质就是对数据库事务的支持,没有数据库事务,Spring是无法提供事务功能的。Spring只提供统一的事务管理接口,具体实现都是由数据库自己实现的,Spring会在事务开始时,根据当前设置的隔离级别,调整数据库的隔离级别,由此保持一致

前言

最近在使用Spring框架时遇到了一些问题,主要是Spring的事务传播问题,一个不带事务的方法调用带事务的方法,有时候会出现不回滚的情况,所以写了这篇文章来记录一下。

7种传播方式

我们先来看Spring事务的7中传播方式以及对应的描述

属性名称描述
PROPAGATION__REQUIREDREQUIRED表示的是当前这个方法必须运行在一个事务环境中,如果当前方法已经处于事务环境中,就可以直接使用该方法,否则开启一个新的事务
PROPAGATION_SUPPORTSSUPPORTS如果当前方法处于事务环境中,就使用当前事务,否则不使用事务
PROPAGATION_MANDATORYMANDATORY表示当前方法一定要处于事务环境中,否则就抛出异常
PROPAGATION_REQUIRES_NEWREQUIRES_NEW当前方法需要运行在新的事务中。如果当前方法已在事务环境中,先暂停当前事务,在启动新的事务方法后才执行该方法,如果当前方法不在事务环境中,就启动一个新的事务后启动执行该方法。
PROPAGATION_NOT_SUPPORTEDNOT_SUPPORTED不支持当前的事务,总是以非事务状态执行。如果这个方法是事务方法,就先挂起这个事务方法,再执行这个方法
PROPAGATION_NEVERNEVER不支持当前事务,如果是事务方法,则抛出异常
PROPAGATION__NESTEDNESTED如果当前执行的方法处于事务环境中,依旧会启动一个事务,嵌套的事务也可以独立于当前事务独立回滚和提交,如果当前执行的方法不在事务环境中,也会启动一个新事务。

注解式事务

在Spring中,我们常用@Transactional来标注一个事务方法,如果有点进去这个注解的源码都可以看到Spring对于添加这个注解的方法,都会默认将这个方法的事务的传播等级设置为REQUIRED,也就是是当前方法必须处于一个事务方法中,或者使用调用这个方法的事务行为。

下面我们来分析下这个注解在什么情况下会失效,并且需要怎么样来去避免这种情况的发生。

事务的方法之间的调用

下面这个例子模仿的是一个带事务的方法调用另外一个事务方法,在下面的这个方法报错,查看当前事务有没有进行回滚

@Override
    @Transactional(rollbackFor = Exception.class)
    public void saveWithDish(SetmealDto setmealDto){
        this.save(setmealDto);
        List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
    }
    @Transactional(rollbackFor = Exception.class)
    public void saveBa(List<SetmealDish> setmealDishes, SetmealDto setmealDto) throws Exception{
        setmealDishes = setmealDishes.stream().peek((item) -> item.setSetmealId(setmealDto.getId())).collect(Collectors.toList());
        setmealDishService.saveBatch(setmealDishes);
        int j = 2/0;
    }

根据事务的传播等级来看,这种情况是肯定可以回滚的,但是如果是同一类中,像下面这种情况,同一个类中一个不带事务的方法调用另外一个带事务的方法,这种情况下它的事务会不会回滚呢?理论上我们觉得是会的,但是在测试的时候呢,我们发现这个事务并没有进行回滚,也就是说,这个事务注解@Transantional没有生效

@Override
    public void saveWithDish(SetmealDto setmealDto) throws Exception{
        List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
        saveBa(setmealDishes, setmealDto);
    }
    @Transactional(rollbackFor = Exception.class)
    public void saveBa(List<SetmealDish> setmealDishes, SetmealDto setmealDto) throws Exception{
        this.save(setmealDto);
        setmealDishes = setmealDishes.stream().peek((item) -> item.setSetmealId(setmealDto.getId())).collect(Collectors.toList());
        setmealDishService.saveBatch(setmealDishes);
        int j = 2/0;
    }

虽然这里我们报错了,但是数据库中还是新增了一条刚刚我们添加的一条数据,这样可以说明,这是没有添加事务的,也验证了上面我们的方法。

下面我们来看情况上,当不同类之间类方法的调用,如果一个事务方法调用一个非事务方法,这样非事务方法当然可以获取到当前这个事务的,不会开启一个新的事务。但是当一个非事务方法调用一个不同类的事务方法时,这样会不会回滚呢,答案是会的,这边我已经进行验证过了。

注意事项

我们需要记住Spring的默认事务传播等级是Required,在Spring扫描Bean时,会扫描这个方法是否带有@Transactional注解,如果是包含的话,Spring会动态生成一个代理类(proxy),当这个方法被调用时,是由代理类来进行调用的,而在初始化时,同一个类下面,这个方法如果是没有带@Transactional注解调用一个@Transactional的方法的话,这个方法的调用是没有经过代理类的,就不会启动transactional,也就是在同一个类出现无效的现象出现

所以,解决的话,我们可以将这两个方法分开到两个不同的类中,所以我们可以知道在一个service类中,如果一个非事务方法调用一个带事务的方法和事务方法之间的相互调用都不会开启新的事务。

到此这篇关于Spring事务传播中嵌套调用实现方法详细介绍的文章就介绍到这了,更多相关Spring嵌套调用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java将CSV的数据发送到kafka的示例

    Java将CSV的数据发送到kafka的示例

    这篇文章主要介绍了Java将CSV的数据发送到kafka得示例,帮助大家更好得理解和使用Java,感兴趣的朋友可以了解下
    2020-11-11
  • struts中动态方法调用使用通配符

    struts中动态方法调用使用通配符

    这篇文章主要介绍了struts中动态方法调用使用通配符的相关资料,非常不错,具有参考借鉴价值,感兴趣的朋友一起看看吧
    2016-09-09
  • Springboot常用注解及配置文件加载顺序详解

    Springboot常用注解及配置文件加载顺序详解

    这篇文章主要介绍了Springboot常用注解及配置文件加载顺序,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-11-11
  • Springboot 2使用外部Tomcat源码分析

    Springboot 2使用外部Tomcat源码分析

    这篇文章主要介绍了Springboot 2使用外部Tomcat源码分析,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-08-08
  • SpringBoot多线程进行异步请求的处理方式

    SpringBoot多线程进行异步请求的处理方式

    这篇文章主要介绍了SpringBoot多线程进行异步请求的处理方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐
    2021-12-12
  • 深入理解Java之jvm启动流程

    深入理解Java之jvm启动流程

    这篇文章主要介绍了深入理解Java之jvm启动流程,文章内容讲解的很清晰,有对这方面感兴趣的同学可以研究下
    2021-02-02
  • Spring中的@EnableConfigurationProperties使用方式以及作用详解

    Spring中的@EnableConfigurationProperties使用方式以及作用详解

    这篇文章主要介绍了Spring中的@EnableConfigurationProperties使用方式以及作用详解,使用了 @ConfigurationProperties 注解的配置类生效,将该类注入到 IOC 容器中,交由 IOC 容器进行管理,此时则不用再配置类上加上@Component,需要的朋友可以参考下
    2024-01-01
  • 浅谈java指令重排序的问题

    浅谈java指令重排序的问题

    下面小编就为大家带来一篇浅谈java指令重排序的问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • Java中的什么场景使用递归,如何使用递归

    Java中的什么场景使用递归,如何使用递归

    这篇文章主要介绍了Java中的什么场景使用递归,如何使用递归的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Java实现学生信息管理界面

    Java实现学生信息管理界面

    这篇文章主要为大家详细介绍了Java实现学生信息管理界面,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06

最新评论