首页 > 其他分享 >spring的事务传播机制

spring的事务传播机制

时间:2023-04-23 21:36:24浏览次数:39  
标签:事务 spring void REQUIRED Exception 传播 Propagation public

spring的事务传播机制

嫌弃内容代码复杂的可直接看思维导图大纲即可

基本概念

指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行

七种行为和测试

PROPAGATION_REQUIRED

默认,当前存在事务,则加入该事务;不存在事务,创建新事务。

public class PropagationService {

    @Autowired
    private
    PropagationMapper propagationMapper;

    @Autowired
    @Lazy
    PropagationService propagationService;

    @Transactional(rollbackFor = Exception.class)
    public void insertPropagationA() throws Exception {
        Propagation propagationA = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationA").build();
        propagationMapper.insert(propagationA);
        propagationServiceSelf.insertPropagationB();
        throw new Exception();
    }

    @Transactional(rollbackFor = Exception.class,propagation = org.springframework.transaction.annotation.Propagation.REQUIRED)
    public void insertPropagationB() throws Exception {
        Propagation propagationB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationB").build();
        Propagation propagationBB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationBB").build();
        propagationMapper.insert(propagationB);
        propagationMapper.insert(prop
@Test
    //Given A传播行为required 和B为required,WHE A发生异常,THEN A插入失败,B插入失败
    public void testRequired() throws Exception {
        propagationService.insertPropagationA();
    }

PROPAGATION_REQUIRED_NEW

始终以新的事务运行,当前存在事务,则挂起原事务;不存在事务,创建新事务

@Test
    //Given 同样代码更改B为required_new, WHE A发生异常, THEN B插入成功,A插入失败
    public void testRequiredNew() throws Exception {
        propagationService.insertPropagationA();
    }

PROPAGATION_SUPPORTS

支持当前事务。当前存在事务,则支持该事务;不存在事务,以非事务方式执行

    @Test
    //Given 更改B为required_supports, A不开启事物, WHE B发生异常, THEN A、B插入成功BB失败;A开启事物因为有异常发生全失败
    public void testRequiredSupports() throws Exception {
        propagationService.insertPropagationA();
    }
//@Transactional(rollbackFor = Exception.class)
    public void insertPropagationA() throws Exception {
        Propagation propagationA = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationA").build();
        propagationMapper.insert(propagationA);
        propagationServiceSelf.insertPropagationB();
        throw new Exception();
    }

    @Transactional(rollbackFor = Exception.class,propagation = org.springframework.transaction.annotation.Propagation.SUPPORTS)
    public void insertPropagationB() throws Exception {
        Propagation propagationB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationB").build();
        Propagation propagationBB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationBB").build();
        propagationMapper.insert(propagationB);
        int a =  1/0;
        propagationMapper.insert(propagationBB);
    }

PROPAGATION_NO_SUPPORTED

非事务方式执行,当前存在事务,则挂起该事务

    @Test
    //Given 更改B为required_not_supports, A开启事物, WHEN A发生异常, THEN A插入失败、B插入成功
    public void testRequiredNotSupports() throws Exception {
        propagationService.insertPropagationA();
    }
    @Transactional(rollbackFor = Exception.class)
    public void insertPropagationA() throws Exception {
        Propagation propagationA = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationA").build();
        propagationMapper.insert(propagationA);
        propagationServiceSelf.insertPropagationB();
        throw new Exception();
    }

    @Transactional(rollbackFor = Exception.class,propagation = org.springframework.transaction.annotation.Propagation.NOT_SUPPORTED)
    public void insertPropagationB() throws Exception {
        Propagation propagationB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationB").build();
        Propagation propagationBB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationBB").build();
        propagationMapper.insert(propagationB);
        propagationMapper.insert(propagationBB);
    }

PROPAGATION_NEVER

非事务方式执行,当前存在事务,则抛出异常();

org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

at org.springframework.transaction.support.AbstractPlatformTransactionManager.handleExistingTransaction(AbstractPlatformTransactionManager.java:413)
    @Transactional(rollbackFor = Exception.class)
    public void insertPropagationA() throws Exception {
        Propagation propagationA = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationA").build();
        propagationMapper.insert(propagationA);
        propagationServiceSelf.insertPropagationB();
        //throw new Exception();
    }

    @Transactional(rollbackFor = Exception.class,propagation = org.springframework.transaction.annotation.Propagation.NEVER)
    public void insertPropagationB() throws Exception {
        Propagation propagationB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationB").build();
        Propagation propagationBB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationBB").build();
        propagationMapper.insert(propagationB);
        propagationMapper.insert(propagationBB);
    }
    @Test
    //Given 更改B为required_never, A开启事物, 调用方法B时报错
    public void testRequiredNever() throws Exception {
        propagationService.insertPropagationA();
    }

PROPAGATION_NESTED

当前存在事务,则嵌套在该事务下起新事务执行;不存在事务,创建新事务。

    @Test
    //Given 更改B为required_nested, A开启事物, 调用方法B,后抛出异常,都失败;A开启事物,调用方法B,B抛出异常,A catch,A成功,B失败
    public void testRequiredNested() throws Exception {
        propagationService.insertPropagationA();
    }
    @Transactional(rollbackFor = Exception.class)
    public void insertPropagationA() throws Exception {
        Propagation propagationA = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationA").build();
        propagationMapper.insert(propagationA);
        try{
            propagationServiceSelf.insertPropagationB();
        }catch(Exception e){

        }
    }

    @Transactional(rollbackFor = Exception.class,propagation = org.springframework.transaction.annotation.Propagation.NESTED)
    public void insertPropagationB() throws Exception {
        Propagation propagationB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationB").build();
        Propagation propagationBB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationBB").build();
        propagationMapper.insert(propagationB);
        int a = 1/0;
        propagationMapper.insert(propagationBB);
    }

PROPAGATION_MANDATORY

事务方式运行,当前不存在事务,则抛出异常

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:362)
//@Transactional(rollbackFor = Exception.class)
    public void insertPropagationA() throws Exception {
        Propagation propagationA = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationA").build();
        propagationMapper.insert(propagationA);
        propagationServiceSelf.insertPropagationB();

    }

    @Transactional(rollbackFor = Exception.class,propagation = org.springframework.transaction.annotation.Propagation.MANDATORY)
    public void insertPropagationB() throws Exception {
        Propagation propagationB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationB").build();
        Propagation propagationBB = Propagation.builder()
                .type("Propagation.REQUIRED")
                .comment("propagationBB").build();
        propagationMapper.insert(propagationB);
        propagationMapper.insert(propagationBB);
    }
    @Test
    //Given 更改B为required_mandatory, WHEN A不开启事物,调用方法B, THEN调用B抛出异常;
    public void testRequiredMandatory() throws Exception {
        propagationService.insertPropagationA();
    }

Transactional失效

spring的事物是基于AOP代理实现的,也就是说背@Transactional修饰的方法所在类会有一个代理类,通过这个代理类实现的。并且也需要底层数据库支持事物,还需要在同一个库中,多个方法运行调用需要在同一个线程中。基于这情况大概失效场景分为两部分

非代理类方向

  • 数据库引擎不支持索引如MyISAm

  • 数据源未配置事物管理器

  • 数据库分布式部署,需要Seata技术解决

  • 多线程,两个事务方法不在同一个线程

代理类方向

  • 类未交给spring,代理自然无法生成

  • 自身调用,相当于this,代理类未生效

  • 事务方法修饰如非public、final、static修饰导致不能被代理

  • 异常类型错误,声明式事务默认对runtimeException、Error才可以触发回滚

  • 对抛出的异常,catch后处理不当。如吞了异常。

  • 设置了错误的传播行为

标签:事务,spring,void,REQUIRED,Exception,传播,Propagation,public
From: https://www.cnblogs.com/yuandian8/p/17347777.html

相关文章

  • SpringBoot 文件打包zip,浏览器下载出去
    本地文件打包@GetMapping("/downloadZip")publicvoiddownloadZip(HttpServletResponseresponse)throwsIOException{try{response.setContentType("application/octet-stream");response.setHeader("......
  • SpringMVC-ssm案例-2023-04-23-2
    Controller其他功能packagecom.feijian.controller;importcom.feijian.pojo.Books;importcom.feijian.service.BookService;importorg.apache.ibatis.annotations.Param;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.b......
  • SpringMVC-ssm案例-2023-04-23
    一、准备工作1.1、搭建普通maven项目,framework的web项目1.2、加载maven依赖:junit-mysql-connector-C3P01                   servlet-jsp/JSTL                 MyBatis  MyBatis-spring  ......
  • 【深入浅出Spring原理及实战】「源码调试分析」深入源码探索Spring底层框架的的refres
    学习Spring源码的建议阅读Spring官方文档,了解Spring框架的基本概念和使用方法。下载Spring源码,可以从官网或者GitHub上获取。阅读Spring源码的入口类,了解Spring框架的启动过程和核心组件的加载顺序。阅读Spring源码中的注释和文档,了解每个类和方法的作用和用法。调试Spring源码,可以......
  • spring 自动装配 default-autowire="byName/byType"[转]
    spring自动装配default-autowire="byName/byType"一、spring自动装配default-autowire="byName"byName,按变量名称,与id名称一样,若不一样,就报错。<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.o......
  • SMU Spring 2023 Trial Contest Round 9
    SMUSpring2023TrialContestRound9A-WrongSubtraction#include<bits/stdc++.h>usingnamespacestd;typedefpair<int,int>PII;typedefpair<string,int>PSI;constintN=1e5+5,INF=0x3f3f3f3f,Mod=1e6;constdoubleeps=1e-6;typedefl......
  • SpringBoot+React 前后端分离
    SpringBoot+React前后端分离写个转发数据的小工具,本来只想开个SpringBoot服务带个页面,但感觉有点难受,正好之前研究了React,尝试一下前后端分离。后端简单用SpringBoot起个服务,写个接口处理请求:@RestController@RequestMapping("/data")publicclassDataController{......
  • SpringIOC理论推导
    IOC理论引入原来实现业务的步骤:Dao层接口Dao层实现类Service层接口Service层实现类eg:Dao层接口publicinterfaceUserDao{voidgetUser();}Dao层实现类publicclassUserDaoImplimplementsUserDao{publicvoidgetUser(){System.ou......
  • 基于SpringBoot+Vue的音乐网站
    本次项目是基于SpringBoot+Vue的前后端分离项目,旨在熟练相关框架,掌握相关技术,拓展个人知识面。音乐来源:本地用户页面:Web项目亮点:根据歌词、音乐旋律、定位时间线(老师的意见)确定好方向,开始项目、收集资料、准备相关的开发环境和软件等。了解项目的结构与逻辑,确定基本功能,需求......
  • springboot~关于md5签名引发的问题
    事实是这样的,我有个接口,这个接口不能被篡改,于是想到了比较简单的md5对url地址参数进行加密,把这个密码当成是sign,然后服务端收到请求后,使用相同算法也生成sign,两个sign相同就正常没有被篡改过。问题的出现接口中的参数包括userId,extUserId,时间,其中extUserId字符编码,中间会有+......