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使用Socket简单通讯详解

    Java使用Socket简单通讯详解

    这篇文章主要介绍了Java使用Socket简单通讯详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • 方法参数属性params,@PathVariable和@RequestParam用法及区别

    方法参数属性params,@PathVariable和@RequestParam用法及区别

    这篇文章主要介绍了方法参数属性params,@PathVariable和@RequestParam用法及区别说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • 解决IDEA项目project包目录消失的问题

    解决IDEA项目project包目录消失的问题

    这篇文章主要介绍了解决IDEA项目project包目录消失的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • Java中SSM框架实现增删改查功能代码详解

    Java中SSM框架实现增删改查功能代码详解

    这篇文章主要介绍了Java中SSM框架实现增删改查功能代码详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • 使用Java注解模拟spring ioc容器过程解析

    使用Java注解模拟spring ioc容器过程解析

    这篇文章主要介绍了使用Java注解模拟spring ioc容器过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • Java编程获取文本框的内容实例解析

    Java编程获取文本框的内容实例解析

    这篇文章主要介绍了Java编程获取文本框的值实例解析,将输入的值保存在一个指定的 txt文件之中,具有一定的参考价值,需要的朋友可以了解。
    2017-09-09
  • SpringMVC如何把后台文件打印到前台

    SpringMVC如何把后台文件打印到前台

    这篇文章主要介绍了SpringMVC如何把后台文件打印到前台,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • Spring Boot 配置 IDEA和DevTools 热部署的方法

    Spring Boot 配置 IDEA和DevTools 热部署的方法

    这篇文章主要介绍了Spring Boot 配置 IDEA和DevTools 热部署的方法,需要的朋友可以参考下
    2018-02-02
  • Spring创建Bean的过程Debug的详细流程

    Spring创建Bean的过程Debug的详细流程

    这篇文章主要介绍了Spring创建Bean的过程Debug的流程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • Springboot使用thymeleaf动态模板实现刷新

    Springboot使用thymeleaf动态模板实现刷新

    这篇文章主要介绍了Springboot使用thymeleaf动态模板实现刷新,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08

最新评论