首页 > 其他分享 >Spring Boot 开启事务支持详细总结

Spring Boot 开启事务支持详细总结

时间:2024-07-17 13:30:03浏览次数:26  
标签:回滚 TransactionDefinition Spring Transactional REQUIRED Boot 事务 开启 public

Spring 对事务的支持

        Spring 支持两种事务方式,分别是编程式事务声明式事务,后者最常见,通常情况下只需要一个 @Transactional 就搞定了(代码侵入性降到了最低),就像这样:

@Transactional
public void savePosts(PostsParam postsParam) {
  // 保存文章
  save(posts);
  // 处理标签
  insertOrUpdateTag(postsParam, posts);
}

编程式事务

编程式事务是指将事务管理代码嵌入到业务代码中,来控制事务的提交和回滚。

使用 TransactionTemplate 来管理事务:

@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction() {

        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {

                try {

                    // ....  业务代码
                } catch (Exception e){
                    //回滚
                    transactionStatus.setRollbackOnly();
                }

            }
        });
}

        就编程式事务管理而言,Spring 更推荐使用 TransactionTemplate。

        在编程式事务中,必须在每个业务操作中包含额外的事务管理代码,就导致代码看起来非常的臃肿,但对理解 Spring 的事务管理模型非常有帮助。

声明式事务

        声明式事务将事务管理代码从业务方法中抽离了出来,以声明式的方式来实现事务管理,对于开发者来说,声明式事务显然比编程式事务更易用、更好用。

        当然了,要想实现事务管理和业务代码的抽离,就必须得用到 Spring 当中最关键最核心的技术之一AOP,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。

        声明式事务虽然优于编程式事务,但也有不足,声明式事务管理的粒度是方法级别,而编程式事务是可以精确到代码块级别的

事务管理模型

        Spring 将事务管理的核心抽象为一个事务管理器(TransactionManager),它的源码只有一个简单的接口定义,属于一个标记接口:

public interface TransactionManager {

}

        该接口有两个子接口,分别是编程式事务接口 ReactiveTransactionManager 和声明式事务接口 PlatformTransactionManager。我们来重点说说 PlatformTransactionManager,该接口定义了 3 个接口方法:

interface PlatformTransactionManager extends TransactionManager{
    // 根据事务定义获取事务状态
    TransactionStatus getTransaction(TransactionDefinition definition)
            throws TransactionException;

    // 提交事务
    void commit(TransactionStatus status) throws TransactionException;

    // 事务回滚
    void rollback(TransactionStatus status) throws TransactionException;
}

        通过 PlatformTransactionManager 这个接口,Spring 为各个平台如 JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。

        参数 TransactionDefinition 和 @Transactional 注解是对应的,比如说 @Transactional 注解中定义的事务传播行为、隔离级别、事务超时时间、事务是否只读等属性,在 TransactionDefinition 都可以找得到。

        返回类型 TransactionStatus 主要用来存储当前事务的一些状态和数据,比如说事务资源(connection)、回滚状态等。

TransactionDefinition.java:

public interface TransactionDefinition {

  // 事务的传播行为
  default int getPropagationBehavior() {
    return PROPAGATION_REQUIRED;
  }

  // 事务的隔离级别
  default int getIsolationLevel() {
    return ISOLATION_DEFAULT;
  }

  // 事务超时时间
  default int getTimeout() {
    return TIMEOUT_DEFAULT;
  }

  // 事务是否只读
  default boolean isReadOnly() {
    return false;
  }
}

Transactional.java

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

  Propagation propagation() default Propagation.REQUIRED;
  Isolation isolation() default Isolation.DEFAULT;
  int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
  boolean readOnly() default false;

}
  • @Transactional 注解中的 propagation 对应 TransactionDefinition 中的 getPropagationBehavior,默认值为 Propagation.REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED)
  • @Transactional 注解中的 isolation 对应 TransactionDefinition 中的 getIsolationLevel,默认值为 DEFAULT(TransactionDefinition.ISOLATION_DEFAULT)
  • @Transactional 注解中的 timeout 对应 TransactionDefinition 中的 getTimeout,默认值为TransactionDefinition.TIMEOUT_DEFAULT。
  • @Transactional 注解中的 readOnly 对应 TransactionDefinition 中的 isReadOnly,默认值为 false。

事务传播行为

        当事务方法被另外一个事务方法调用时,必须指定事务应该如何传播,例如,方法可能继续在当前事务中执行,也可以开启一个新的事务,在自己的事务中执行。

声明式事务的传播行为可以通过 @Transactional 注解中的 propagation 属性来定义,比如说:

@Transactional(propagation = Propagation.REQUIRED)
public void savePosts(PostsParam postsParam) {
}

TransactionDefinition 一共定义了 7 种事务传播行为:

1、PROPAGATION_REQUIRED(默认)

  • 如果外部方法没有开启事务的话,Propagation.REQUIRED 修饰的内部方法会开启自己的事务,且开启的事务相互独立,互不干扰。
  • 如果外部方法开启事务并且是 Propagation.REQUIRED 的话,所有 Propagation.REQUIRED 修饰的内部方法和外部方法均属于同一事务 ,只要一个方法回滚,整个事务都需要回滚。
    Class A {
        @Transactional(propagation=Propagation.PROPAGATION_REQUIRED)
        public void aMethod {
            //do something
            B b = new B();
            b.bMethod();
        }
    }
    
    Class B {
        @Transactional(propagation=Propagation.PROPAGATION_REQUIRED)
        public void bMethod {
           //do something
        }
    }
    

    这个传播行为也最好理解,aMethod 调用了 bMethod,只要其中一个方法回滚,整个事务均回滚。

2、PROPAGATION_REQUIRES_NEW

        创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法都会开启自己的事务,且开启的事务与外部的事务相互独立,互不干扰。

Class A {
    @Transactional(propagation=Propagation.PROPAGATION_REQUIRED)
    public void aMethod {
        //do something
        B b = new B();
        b.bMethod();
    }
}

Class B {
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void bMethod {
       //do something
    }
}

        如果 aMethod()发生异常回滚,bMethod()不会跟着回滚,因为 bMethod()开启了独立的事务。但是,如果 bMethod()抛出了未被捕获的异常并且这个异常满足事务回滚规则的话,aMethod()同样也会回滚。

3、PROPAGATION_NESTED

        如果当前存在事务,就在当前事务内执行;否则,就执行与 PROPAGATION_REQUIRED 类似的操作。

4、PROPAGATION_MANDATORY

        如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

5、PROPAGATION_SUPPORTS

        如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

6、PROPAGATION_NOT_SUPPORTED

        以非事务方式运行,如果当前存在事务,则把当前事务挂起。

7、PROPAGATION_NEVER

        以非事务方式运行,如果当前存在事务,则抛出异常。

事务隔离级别

  • ISOLATION_DEFAULT,使用数据库默认的隔离级别,MySql 默认采用的是 REPEATABLE_READ,也就是可重复读。
  • ISOLATION_READ_UNCOMMITTED,最低的隔离级别,可能会出现脏读、幻读或者不可重复读。
  • ISOLATION_READ_COMMITTED,允许读取并发事务提交的数据,可以防止脏读,但幻读和不可重复读仍然有可能发生
  • ISOLATION_REPEATABLE_READ,对同一字段的多次读取结果都是一致的,除非数据是被自身事务所修改的,可以阻止脏读和不可重复读,但幻读仍有可能发生
  • ISOLATION_SERIALIZABLE,最高的隔离级别,虽然可以阻止脏读、幻读和不可重复读,但会严重影响程序性能

事务的超时时间

        事务超时,也就是指一个事务所允许执行的最长时间,如果在超时时间内还没有完成的话,就自动回滚。

        假如事务的执行时间格外的长,由于事务涉及到对数据库的锁定,就会导致长时间运行的事务占用数据库资源。

事务的只读属性

        如果一个事务只是对数据库执行读操作,那么该数据库就可以利用事务的只读属性,采取优化措施,适用于多条数据库查询操作中。

为什么一个查询操作还要启用事务支持呢?

        这是因为 MySql(innodb)默认对每一个连接都启用了 autocommit 模式,在该模式下,每一个发送到 MySql 服务器的 SQL 语句都会在一个单独的事务中进行处理,执行结束后会自动提交事务。

        那如果我们给方法加上了 @Transactional 注解,那这个方法中所有的 SQL 都会放在一个事务里。否则,每条 SQL 都会单独开启一个事务,中间被其他事务修改了数据,都会实时读取到。

        有些情况下,当一次执行多条查询语句时,需要保证数据一致性时,就需要启用事务支持。否则上一条 SQL 查询后,被其他用户改变了数据,那么下一个 SQL 查询可能就会出现不一致的状态。

事务的回滚策略

        默认情况下,事务只在出现运行时异常(Runtime Exception)时回滚,以及 Error,出现检查异常(checked exception,需要主动捕获处理或者向上抛出)时不回滚。

        如果你想要回滚特定的异常类型的话,可以这样设置:

@Transactional(rollbackFor= MyException.class)

关于 Spring Boot 对事务的支持

@Transactional 的作用范围

  • 类上,表明类中所有 public 方法都启用事务
  • 方法上,最常用的一种
  • 接口上,不推荐使用

@Transactional的常用配置参数

        @Transactional 注解源码中定义了很多属性,但大多数时候,我都是采用默认配置,当然了,如果需要自定义的话,前面也都说明过了。

@Transactional 的使用注意事项总结

  • 要在 public 方法上使用,在AbstractFallbackTransactionAttributeSource类的computeTransactionAttribute方法中有个判断,如果目标方法不是public,则TransactionAttribute返回null,即不支持事务。
  • 避免同一个类中调用 @Transactional 注解的方法,这样会导致事务失效。

标签:回滚,TransactionDefinition,Spring,Transactional,REQUIRED,Boot,事务,开启,public
From: https://blog.csdn.net/qq_62636650/article/details/140473191

相关文章

  • 【2024】springboot Home F家居系统的设计与管理
    博主介绍:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌技术范围:SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数......
  • springboot整合第三方框架
    1.整合mybatis引入依赖<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--mysq......
  • spring boot的基础入门
    1.什么是springbootspringboot也是spring公司开发的一款框架。为了简化spring项目的初始化搭建的。spring项目搭建的缺点:[1]配置麻烦[2]依赖[3]tomcat启动慢2.springboot的特点1)自动配置SpringBoot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过......
  • Spring事务原理、Spring事务传播机制
    Spring的@EnableTransactionManagement和@Transactional原理@Configuration@EnableTransactionManagementpublicclassAppConfig{//配置类内容}@ServicepublicclassMyService{@TransactionalpublicvoidprocessPayment(Payment......
  • 面试官:为什么SpringBoot的 jar 可以直接运行?
    引言传统Java应用部署:需要将应用打包成WAR文件,部署到如ApacheTomcat、Jetty等Web容器中。SpringBoot:改变了Java应用的开发体验,应用可以打包成可直接运行的jar文件,无需外部容器。SpringBootJAR包基础概念FatJAR(胖Jar):包含应用程序所需的全部依赖库和应用程序自身的......
  • Java面试 (5) :SSM(Spring框架、Spring MVC、MyBatis…)
    Java面试——SSM基础知识:Spring框架、SpringMVC、MyBatis…文章目录1String框架1.1IOC和DI1.2Bean1.2.1作用域1.2.2自动装配模式1.2.3生命周期1.2.3.1doGetBean()源码1.2.3.2七个阶段详解1.2.4Bean线程安全1.3常用的Spring注解1.4事务1.4.1Spring事务......
  • 基于ssm的springboot摄影约拍系统的设计实现(源码+LW+部署讲解)
    前言......
  • Spring Boot+Redis 分布式锁:模拟抢单
    如何删除锁模拟抢单动作(10w个⼈开抢)jedis的nx⽣成锁对于java中想操作redis,好的⽅式是使⽤jedis,⾸先pom中引⼊依赖:<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency>对于分布式锁的⽣成通常......
  • 基于web的人力资源管理系统 毕业设计 springboot+Vue+mysql
    介绍在当今企业管理中,人力资源的有效管理对于组织的发展至关重要。为了提高人力资源管理的效率和准确性,我们开发了这个基于Web的人力资源管理系统。该系统旨在为企业提供一个全面、便捷、高效的人力资源管理平台,满足企业对人力资源规划、招聘、培训、绩效管理等方面的需求。......
  • 基于springboot的社区智慧养老监护管理平台 毕业设计 springboot+Vue+mysql
    介绍随着人口老龄化的加剧,养老服务的需求日益增长,传统的养老模式已经难以满足现代社会的需求。为了提供更高效、便捷、个性化的养老服务,我们开发了这个基于SpringBoot的社区智慧养老监护管理平台。该平台旨在整合社区养老资源,实现对老年人的全面监护和管理,提升养老服务的质......