• 对Spring事务一些问题的讨论


      提起spring事务,就会让人联想起四大基本特征,五个隔离级别,七大传播特性。相信大多数人都知道这些东西,但是知道是一回事情,能用好真的是另一回事了。在使用Spring事务的时候,我曾遇到过几个比较严肃的问题,在这里我做一个自我总结。

     

    问题一、 propagation.NESTED和propagation.REQUIRED_NEW有什么区别?

      当调用方不存在事务的时候,两者的效果是一致的。所以这里讨论问题的前提是调用方存在事务。PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行. 
    另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交. 
    由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back. 

    问题二、 @Transactional为什么会失效?

      1.调用方和被调用方属于同一个component,被调用方的 @Transacational注解无效

      

    package com.transacational;
    
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.annotation.Transactional;
    
    /**
     * Created by chenqimiao on 17/10/31.
     */
    @Component
    public class Service {
    
        public void test1(){
            test2();
        }
    
        @Transactional//此处的注解无效
        public void test2(){
    
        }
    }

      2.被调用方不是一个public方法,被调用方的 @Transacational注解无效  

    @Component
    public class Service {
    
        @Resource
        private Service1 service1;
        
        public void test1(){
            test2();
            service1.test3();
        }
    
        @Transactional//1.此处的注解无效
        public void test2(){
    
        }
    }
    package com.transacational;
    
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.annotation.Transactional;
    
    /**
     * Created by chenqimiao on 17/10/31.
     */
    @Component
    public class Service1 {
    
        @Transactional//2.此处注解无效
        protected void test3(){
    
        }
    }

      

      3.未开启事务开关,如:在SpringBoot中,启动类未使用 @EnableTransactionManagement

     

    问题三、 如何理解@Transactional的超时时间?

       timeout是一个供开发者设置超时时间的属性。默认值-1,超时时间由具体的sql系统决定。   

    /**
     * Created by chenqimiao on 17/10/31.
     */
    @Component
    public class Service3 {
    
    
        @Resource
        private AdminInfoDoMapper adminInfoDoMapper;
        @Transactional(timeout = 4)//并不会超时
        public void test4(){
    
            adminInfoDoMapper.selectNameById(1);
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    超时时间具体的定义:事务开始(在该方法第一句代码执行之前)到最后一个Statement执行完毕

    所以象下面这样写,事务就会超时

    @Component
    public class Service3 {
    
    
        @Resource
        private AdminInfoDoMapper adminInfoDoMapper;
        @Transactional(timeout = 4)
        public void test4(){
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            adminInfoDoMapper.selectNameById(1);
    
        }
    }

    问题四、 @Transactional默认的回滚策略?

    默认情况下,只有当RuntimeException或其子类的异常被事务捕获之后,事务才会回滚,如果要让事务能够回滚所有异常,必须手动指定  @Transactional(rollbackFor=Exception.class)  ,这样继承Exception的子类或者Exception本身都可以让事务回滚。

  • 相关阅读:
    pair和map
    lower_bound( )和upper_bound( )
    P1886 滑动窗口 /【模板】单调队列
    数的度(数位dp)
    最小生成树
    刷题-力扣-1052. 爱生气的书店老板
    刷题-力扣-766. 托普利茨矩阵
    刷题-力扣-28. 实现 strStr()
    刷题-力扣-697. 数组的度
    刷题-力扣-1004. 最大连续1的个数 III
  • 原文地址:https://www.cnblogs.com/think-in-java/p/7764910.html
Copyright © 2020-2023  润新知