• spring的事务传播机制


    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开启事物,调用方法BB抛出异常,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后处理不当。如吞了异常。

    • 设置了错误的传播行为

  • 相关阅读:
    逮到一个阿里 10 年老 测试开发,聊过之后收益良多...
    无主复制系统(1)-节点故障时写DB
    传统算法与神经网络算法,神经网络算法有什么用
    C语言 深度探究C语言中的I/O
    y106.第六章 微服务、服务网格及Envoy实战 -- 可观测应用之指标和日志(十七)
    MyBatis-Plus分页插件和使用Mapper文件
    SQLiteC/C++接口详细介绍之sqlite3类(八)
    MySQL的级联操作
    【科研主题检索】借助多方翻译软件,融合给出的研究主题对象的翻译结果确定检索式
    基于node.js自动写入版本号解决前端vue或webpack项目因分包发版引起的报错问题
  • 原文地址:https://www.cnblogs.com/yuandian8/p/17347777.html