• Spring中事务几个常见的问题


    首先,事务这个概念是数据库层面的,Spring只是基于数据库中的事务进行扩展,以及提供了一些能让程序员更新方便操作事务的方式

    Spring如何处理事务

    Spring中支持编程式事务和声明式事务管理两种方式

    1、编程式事务,可以使用TransactionTemplate

    public class B {
        @Autowired
        private TransactionTemplate template;
        
        public void sout(){
            TransactionCallback<Integer> transactionCallback = new TransactionCallback<Integer>() {
                @Override
                public Integer doInTransaction(TransactionStatus transactionStatus) {
                    //jdbcTemplate.update
                    //jdbcTemplate.update
                    if(执行失败){
                        //回滚事务
                        transactionStatus.setRollbackOnly();
                        return -1;
                    }
                    return 1;
                }
            };
    
            Integer result =  template.execute(transactionCallback);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    当加了@Transactional注解后,Spring会基于这个类生成一个代理对象,会将这个代理对象作为bean,当在使用这个代理对象的方法时,如果这个方法上存在@Transactional注解,那么代理逻辑会先把事务的自动提交设置为false,然后再去执行原本的业务逻辑方法,如果执行业务逻辑方法没有出现异常,那么代理逻辑中就会将事务提交,如果执行业务逻辑方法出现了异常,那么会将事务进行回滚。

    好处:代码级别的事务控制,可以自己控制事务的逻辑,比较灵活
    缺点:太麻烦,需要自己实现所有的事务逻辑

    2、声明式事务

    是Spring在AOP基础上提供的事务实现机制。

    public class B {
        @Autowired
        private TransactionTemplate template;
    
        @Transactional
        public void sout(){
      System.out.println("=================A=====================");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    优点:不需要在业务代码中添加事务管理的代码,只需要在配置文件中做相关的事务规则声明规则就可以了。
    缺点:只能只能针对方法级别,无法控制代码级别。

    Spring事务如何实现

    Spring事务底层是基于数据库事务和AOP机制实现的

          首先,对于使用了@Transactional注解的bean,Spring会创建一个代理对象作为bean
          当调用代理方法时,会先判断方法上是否加了@Transactional注解
          如果加了,那么利用事务管理器会创建一个数据库连接
          并且修改数据库连接的autoCommit属性我false,禁止此连接自动提交,这是实现Spring事务非常重要的一步
          然后会执行当前方法,方法中会执行SQL
          执行完当前方法后,如果没有出现异常就直接提交事务
          如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务
          Spring事务的隔离级别对应的就是数据库的隔离级别
          Spring事务的传播机制是Spring自己实现的,也是Spring事务中最复杂的
          Spring事务的传播机制是基于数据库连接来做的,一个数据库连接就是一个事务,如果传播机制配置为需要拆开一个事务,那么实际上就是新建立一个数据库连接,在此新数据库连接上执行SQL

    Spring事务传播机制

    Propagation:多个事务方法相互调用时,事务是如何在这些方法键传播

    方法A是一个事务方法。方法A在执行的过程中调用了方法B,那么方法B有无事务以及方法B对事物的要求不同都会对方法A的事务具体执行造成影响,同时方法A的事务对方法B的事务执行也有影响。这种影响具体是什么就由两个方法所定义的事务传播类型所决定

    a调用b,以下描述,当前均只a,自己均指b

    REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务。

    SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行

    MANDATORY:当前存在事务,则加入当前事务,如果当前没有事务,则抛出异常

    REQUIRES_NEW:创建一个新事务,如果存在当前事务,则挂起该事务(互不干扰)

    NOT_SUPPORTED:以非事务方法执行,如果当前存在事务,则挂起当前事务。

    NEVER:不使用事务,如果当前存在事务,则抛出异常

    NESTED:如果当前存在事务,则嵌套事务中执行,否则REQUIRED操作一样(开启一个事务)

    和REQUIRES_NEW的区别
    REQUIRES_NEW是新建一个事务,并且新开启的事务与原事务无关,而NESTED则是当前存在事务时(我们把当前事务成为父事务)会开启一个嵌套事务(称之为一个子事务)。在NESTED情况下父事务回滚时,子事务也会回滚,而在REQUIRES_NEW情况下,原有事务回滚,不会影响新开启的子事务。

    和REQUIRED的区别
    REQUIRED情况下,调用方存在事务时,则被调用和调用方法使用同一事务,那么被调用方出现异常时,由于共用一个事务,所以无论调用方法是否catch异常,事务都会回滚(父子事务一起回滚),而在NESTED情况下,被调用方发生异常时,调用发可以catch其异常,这样只有子事务回滚,父事务不受影响(父事务是否需要回滚可以自行决定)

    Spring事务隔离级别

    ISOLATION:Spring的事务隔离级别
    DEFAULT:使用数据库默认的事务隔离级别

    READ_UNCOMMITTED:读未提交,允许事务在执行过程中,读取其他事务未提交的数据

    READ_COMMITTED:读已提交,允许事务在执行过程中,读取其他事务已提交的数据

    REPEATABLE_READ:可重复读,在同一个事务内,任意时刻的查询结果是一致的

    SERIALIZABLE:所有事务依次执行

    数据库配置的隔离级别是read commited,而spring配置的隔离级别是repeatable read,这个时候隔离级别以哪个为准?
    以Spring为准(spring配置的会覆盖数据库的隔离级别),如果Spring配置的隔离级别数据库不支持,效果取决于数据库

    Spring事务什么时候会失效

    Spring事务的原理是AOP,进行了切面增强,那么失效的根本原因是AOP不起作用了,常见的情况有如下几种:
    1、发生自调用
    类里面使用this调用本类的方法(this通常省略),此时这个this对象不是代理类,而是当前对象本身
    解决方法很简单,让this变成对应的代理类即可

    2、方法为private
    @Transactional底层cglib是基于父子类来实现的,子类是不能重载父类的private方法的,所以无法很好的利用代理,也会导致@Transactional失效

    3、数据库不支持事务
    Spring的事务是基于数据库的事务的,如果数据库不支持事务,Spring再怎么操作也是没有用的

    4、没有被Spring管理
    虽然在方法中增加了@Transactional,但是对应的类没有加到Spring容器中

    5、异常被catch掉
    事务不会回滚(或者抛出的异常没有被定义,默认为RuntimeException)

  • 相关阅读:
    Shell文件包含
    [100天算法】-和为 K 的子数组(day 39)
    二叉树的循环问题
    【Dubbo】入门搭建
    表格、表格样式与长表格
    驱动开发4 使用字符设备驱动的分步实现编写LED驱动(LED亮灯)
    【云原生-Kurbernetes篇】K8s的存储卷/数据卷+PV与PVC
    【Spring Boot 集成应用】Redis的集成用法
    十一、python实现单例模式
    什么耳机适合华为手机?适合华为手机的蓝牙耳机推荐
  • 原文地址:https://blog.csdn.net/sxl123sxl/article/details/126109796