当前位置: 首页 > web >正文

Spring 基于注解的自动化事务

Spring 基于注解的自动化事务

  • 事务
    • 开启事务自动化管理
    • 声明式事务
    • **回滚的默认机制?**
    • @Transacitonal注解属性
    • 注解属性:
      • 事务管理器:transactionManager
        • 原理
        • 举例:PlatformTransactionManager接口方法说明
        • 核心:事务拦截器TransactionInterceptor
      • ★隔离级别
        • 隔离级别的作用?
        • 隔离级别分为?
        • 读未提交(Isolation.READ_UNCOMMITTED)
        • 读已提交(Isolation.READ_COMMITTED)
        • 可重复读(Isolation.REPEATABLE_READ)
      • ★传播行为
        • 概述
        • 传播行为详解
        • 总结与对比
      • timeout(同timeoutString):控制事务的超时时间
      • readOnly:只读优化
      • rollbackFor(rollbackForClassName):指定哪些编译异常需要回滚
      • noRollbackFor(noRollbackForClassName):指明异常不回滚


  • 参考连接:https://www.bilibili.com/video/BV14WtLeDEit/?p=80&share_source=copy_web&vd_source=053075eb8bd04ebb7bc161d3f4386d4f

事务

开启事务自动化管理

  • 在SpringBoot启动类上,添加注解@EnableTransactionManagement
package com.ssg.tx;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;// 开启基于注解的自动化事务管理
@EnableTransactionManagement
@SpringBootApplication
public class SsgTxApplication {public static void main(String[] args) {SpringApplication.run(SsgTxApplication.class, args);}}

声明式事务

声明式 vs 编程式

  • 编程式:通过编写业务代码,程序员自行完成指定功能
  • 声明式:通过声明业务需求,框架自动完成指定功能

声明式事务

  • 定义:只需要告诉框架,这个方法需要事务,框架会自动在运行方法时执行事务的流程控制逻辑。
  • Spring支持:@Transactional
  • @Transactional属性

回滚的默认机制?

  • 运行时异常,事务进行回滚。例如:空指针异常
  • 编译时异常,事务不会滚。例如:IO异常

@Transacitonal注解属性

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Reflective
public @interface Transactional {// 事务管理器,别名为transactionManager@AliasFor("transactionManager")String value() default "";// 事务管理器,别名为value@AliasFor("value")String transactionManager() default "";String[] label() default {};Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default -1;String timeoutString() default "";boolean readOnly() default false;Class<? extends Throwable>[] rollbackFor() default {};String[] rollbackForClassName() default {};Class<? extends Throwable>[] noRollbackFor() default {};String[] noRollbackForClassName() default {};
}

注解属性:

事务管理器:transactionManager

  • 事务管理器是控制事务提交回滚的。
原理
  • Spring 在运行时通过事务拦截器(TransactionInterceptor)根据 @Transactional 的限定符或 Bean 名称 找到对应的事务管理器 Bean,并由该事务管理器真正驱动事务。
  • 默认不指定限定符时,Spring 会按照类型匹配唯一的事务管理器 Bean;若存在多个同类型 Bean,则必须显式用限定符或名字区分。
  • 连接池(DataSource) 仅提供物理数据库连接;事务管理器依赖连接池。 事务管理器(DataSourceTransactionManager)里有一个字段 dataSource,启动时就会注入一个 DataSource(通常就是连接池 HikariDataSource)。
  • 事务管理器离不开这个 DataSource;没有它,事务管理器连数据库都连不上,更别提 commit/rollback。
  • 连接池(HikariDataSource)本身并不知道也不关心“事务管理器”是谁。它只负责给出 Connection,至于这连接是被事务管理器用、还是被你自己裸用,它根本无所谓。
  • 连接池并不依赖事务管理器,可以独立存在。这就是“事务管理器依赖连接池,而非连接池去选择事务管理器”的含义。
  • 事务管理器接口的选用与数据库访问技术有关:
    • 关系型数据库(JDBC、Hibernate、MyBatis 等)→ 默认实现 PlatformTransactionManager
    • 响应式数据库(R2DBC、Mongo-Reactive 等)→ 实现 ReactiveTransactionManager
  • 多数据源场景下,必须为每个 DataSource 显式声明一个独立的事务管理器 Bean,并用 @Qualifier 或限定符注解区分,防止将 MySQL 的事务管理器误用于 Oracle 数据库。

  • 注意看注释PlatformTransactionManagerReactiveTransactionManager
	/*** @see #value* @see org.springframework.transaction.PlatformTransactionManager* @see org.springframework.transaction.ReactiveTransactionManager*/@AliasFor("value")String transactionManager() default "";
  • transactionManager:事务管理器;控制事务的获取、提交、回滚。

底层默认使用哪个事务管理器?

  • 根据数据源的不同,选择不同的事务管理器。
  • 传统的JDBC/Mybatis这类阻塞式事务:选择PlatformTransactionManager
  • 对应R2DBC、Mongo-Reactive这类响应式事务:选择ReactiveTransactionManager
举例:PlatformTransactionManager接口方法说明
public interface PlatformTransactionManager extends TransactionManager {// TransactionStatus:返回事务的连接信息、数据库的连接信息TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;void commit(TransactionStatus status) throws TransactionException;void rollback(TransactionStatus status) throws TransactionException;
}
  • getTransaction()方法:作用:Spring 每次进入带有 @Transactional 的方法时,都会先调用它来 拿或开一个事务。返回值 TransactionStatus 里保存了当前连接(数据库连接,也可以理解为获取了一次数据库会话)、是否为新事务、是否已完成等内部信息
  • commit()方法作用:当业务方法正常返回、没有抛异常时,Spring 会调用它 提交 事务。这里的 status 就是刚才 getTransaction 返回的那个对象,里面记录了要提交哪一个连接/会话。
  • rollback()方法作用:业务方法抛出运行时异常或受检异常(满足 rollback-rules)时,Spring 会调用它 回滚 事务。同样靠 status 找到对应的连接/会话来执行回滚。
核心:事务拦截器TransactionInterceptor
  • org.springframework.transaction.interceptor.TransactionInterceptor
  • 事务的底层原理是一个切面。
  • 核心:控制事务何时提交与回滚。他是一个编程方式的切面,不是注解式的切面。
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
}
  • MethodInterceptor:是 Spring AOP 的核心拦截器接口,也被事务模块(TransactionInterceptor)实现。
  • MethodInterceptor.invoke(...) 就是 Spring 给所有“方法级横切逻辑”(事务、权限、日志等)提供的统一钩子;TransactionInterceptor 利用这个钩子把声明式事务织入到业务方法的前后。

★隔离级别

隔离级别的作用?

为了防止当多个事务读写并发的时候出现的脏读、不可重复读、幻读问题的。

隔离级别分为?
  • 读已提交:事务只会读取已经提交的数据,可避免脏读,但可能引发不可重复度和幻读。
  • 读未提交:事务可以读取未提交的数据,易产生脏读、不可重复度和幻读。
  • 可重复读:同一事务期间多次重复读取的数据相同。避免脏读和不可重复读,但仍有幻读的问题
  • 串行化:最高隔离级别,完全禁止并发,只允许一个事务执行完毕之后才能执行另一个事务
级别问题脏读不可重复读幻读
读已提交×
读未提交
可重复读××
串行化×××

级别问题解读:

  • 脏读:读到别人未提交的数据。
  • 不可重复读:同一行两次内容不同别人已提交更新)。
  • 幻读:同一范围两次行数不同别人已提交增删)。
读未提交(Isolation.READ_UNCOMMITTED)
@Transactional(isolation = Isolation.READ_UNCOMMITTED)

代码可以通过隔离级别,读取到事务未提交的数据

  • 容易产生脏读(第一次与最终结果不一样)、不可重复读(多次读取到的数据不一样)
  • 既能提交到脏数据,又导致了不可重复读,幻读。
读已提交(Isolation.READ_COMMITTED)
@Transactional(isolation = Isolation.READ_COMMITTED)

只能读取到别人已经提交的数据

  • 会导致不可重复读(别人提交的数据)和幻读。
可重复读(Isolation.REPEATABLE_READ)
  • 也叫:快照读
  • Mysql数据库事务,默认级别为:可重复读。
  • Oracle数据库事务,默认级别为:读已提交。
@Transactional(isolation = Isolation.REPEATABLE_READ)

一个方法内存在多个同SQL方法,依次执行同一个sql方法,数据结果始终一致。(在这个方法执行期间,可以无法读取到其他方法已提交的结果

  • 只要事务不结束,读取到的数据结果从头到尾都是同一个。即使外界将这条数据删除,也是同一个结果。

★传播行为

传播行为定义这个方法该怎么用一个事务,大事务是否会影响我,我要不要事务。

  • 应用场景:一个增删改方法里面,调用另一个增删改方法。(大事务里面套用另一个小事务),事务的嵌套问题,也就需要用传播行为来控制。

好的,这是对 Propagation 枚举(事务传播行为)的中文详细解释:


概述

Propagation 枚举定义了 Spring 事务的传播行为(Propagation Behavior)。它决定了当一个事务方法被另一个事务方法调用时,事务应该如何传播。例如,是加入现有事务,还是挂起现有事务并开启一个新事务。这是 Spring 事务管理中非常核心且强大的一个概念。


传播行为详解
  1. REQUIRED (需要事务)

    • 行为如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
    • 说明: 这是最常用的默认设置。它保证了方法一定在一个事务中运行。如果多个方法都使用 REQUIRED 并且相互调用,它们会共享同一个物理事务。如果其中任何一个方法发生回滚,整个事务都将回滚。
    • 适用场景: 绝大多数需要进行数据库写操作的场景。
  2. SUPPORTS (支持事务)

    • 行为如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式继续执行。
    • 说明: 该方法对事务没有强制要求,“有就用,没有就算了”。它依赖于调用方的事务上下文。
    • 注意: 即使以非事务方式运行,它仍然会参与事务同步(如绑定同一数据库连接),这与完全没有事务注解的方法略有不同。
    • 适用场景: 主要用于查询方法。如果调用方有事务,则查询在该事务内执行(保证一致性视图);如果没有,直接执行查询(效率更高)。
  3. MANDATORY (强制要求事务)

    • 行为如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
    • 说明: 该方法强制要求必须在一个已有的事务中被调用。它自己不会发起新事务。
    • 适用场景: 用于必须作为更大事务的一部分来执行的方法,如果被非事务方法误调用,它会立即抛出异常以提醒开发者。
  4. REQUIRES_NEW (需要新事务)

    • 行为无论如何都会创建一个新的事务。如果当前存在事务,则将其挂起。
    • 说明: 该方法总会启动一个独立的、全新的物理事务。新事务与旧事务完全隔离,互不影响。新事务提交或回滚后,旧事务再恢复执行。
    • 注意事务挂起操作需要事务管理器的支持(如 JtaTransactionManager 需要服务器提供 TransactionManager)。
    • 适用场景: 需要独立提交、不受外部事务失败影响的逻辑,例如日志记录(即使业务失败,日志仍需记录入库)。
  5. NOT_SUPPORTED (不支持事务)

    • 行为以非事务方式执行。如果当前存在事务,则将其挂起。
    • 说明: 该方法强制不在事务中运行。它会挂起任何现有的事务,等自己非事务执行完毕后,再恢复原事务。
    • 注意: 同样需要事务管理器支持挂起操作。
    • 适用场景: 需要在不干扰调用方事务的情况下,执行某些不需要事务支持的操作(例如调用一个不支持事务的第三方服务)。
  6. NEVER (绝不)

    • 行为以非事务方式执行。如果当前存在事务,则抛出异常。
    • 说明: 该方法不仅自己不以事务方式运行,还坚决不允许调用方在有事务的情况下调用它。
    • 适用场景: 用于明确不应该在任何事务中执行的方法,防止误用。
  7. NESTED (嵌套事务)

    • 行为如果当前存在事务,则在其内部创建一个嵌套事务(保存点)来执行;如果当前没有事务,则其行为与 REQUIRED 一样。
    • 说明: 这是一个非常特殊的行为。嵌套事务是外部事务的一个子事务,它的提交会随外部事务一起提交。但它的回滚是部分回滚,只会回滚到它自己创建的保存点,而不会导致整个外部事务回滚。外部事务的回滚则会回滚所有嵌套事务。
    • 注意并非所有事务管理器都支持嵌套事务。主要支持 JDBC 的 DataSourceTransactionManager(通过保存点实现)。JTA 事务管理器需要看具体厂商实现。
    • 适用场景: 适用于一个复杂业务中,某些步骤可以独立失败而不影响整体主流程的场景。例如,处理一个订单列表,其中某单个订单处理失败不应回滚所有已成功处理的订单,但整个批量处理任务本身失败则应全部回滚。

总结与对比
传播行为当前有事务当前无事务特点
REQUIRED (默认)加入创建新事务保证在事务中运行
SUPPORTS加入非事务运行跟随调用方,不强制
MANDATORY加入抛出异常强制必须在事务中
REQUIRES_NEW挂起并创建新事务创建新事务创建独立的新事务
NOT_SUPPORTED挂起并非事务运行非事务运行强制非事务运行
NEVER抛出异常非事务运行禁止在事务中运行
NESTED嵌套事务 (保存点)创建新事务部分提交/回滚

选择正确的传播行为对于构建健壮、符合预期的事务应用程序至关重要。

timeout(同timeoutString):控制事务的超时时间

  • timeout:事务超时,以秒为单位,int类型。
  • timeoutString:string类型
  • 一旦超过约定时间,事务就会回滚。
  • 超时时间是指:从方法开始,到最后一次数据库操作结束的时间。
    @Transactional(timeout = 3, timeoutString = "3")

readOnly:只读优化

  • 如果整个事务都是读操作,底层会开启一个只读优化。
  • 如果readOnly,为true,则开启只读优化,默认为false。

rollbackFor(rollbackForClassName):指定哪些编译异常需要回滚

Class<? extends Throwable>[] rollbackFor() default {};
  • 指明哪些异常需要回滚,不是所有异常都一定会引起事务回滚。

异常分类?

  • 运行时异常
  • 编译时异常
    @Transactional(rollbackFor = {IOException.class}, rollbackForClassName = "java.lang.Exception")
  • 回滚 = 运行时异常 + 指定异常

noRollbackFor(noRollbackForClassName):指明异常不回滚

  • 不回滚 = 编译时异常 + 指定的不回滚异常
  • 正常情况下,所有运行时异常都会进行回滚。
  • 我们使用noRollbackFor,可以使部分运行时异常不回滚。
    @Transactional(noRollbackFor = {RuntimeException.class}, noRollbackForClassName = {"java.lang.RuntimeException"})
http://www.xdnf.cn/news/20425.html

相关文章:

  • JBoltAI:解锁企业AI数智化升级的Java利器
  • 算法与数据结构实战技巧:从复杂度分析到数学优化
  • 13-Java-面向对象-封装和this关键字
  • Jenkins运维之路(自动获得分支tag自动构建)
  • ComfyUI Easy - Use:简化ComfyUI操作的得力插件
  • echarts实现点击图表添加标记
  • MySQL MHA 高可用集群搭建
  • 5.物理服务器搭建FC
  • 决策树概念与原理
  • MySQL DBA需要掌握的 7 个问题
  • Windows权限提升(二)
  • 深蓝汽车人事调整:邓承浩升任董事长,姜海荣出任首席执行官
  • 【LeetCode热题100道笔记】对称二叉树
  • 跨域彻底讲透
  • ThinkPHP 6框架常见错误:htmlentities()函数参数类型问题解决
  • 【pyhton】函数
  • [Godot入门大全]目录
  • 【杂类】I/O
  • MiniDrive:面向自动驾驶的更高效的视觉语言模型
  • css 十大常用英文字体
  • Swift 解法详解 LeetCode 362:敲击计数器,让数据统计更高效
  • 2025高教社国赛数学建模A题参考论文35页(含代码和模型)
  • 【算法--链表】86.分割链表--通俗讲解
  • Linux基础知识(二)
  • Python毕业设计推荐:基于Django的饮食计划推荐与交流分享平台 饮食健康系统 健康食谱计划系统
  • Gutenberg块编辑器:WordPress 2025高效内容开发指南
  • 小智AI编译
  • Hadoop(八)
  • 02-Media-6-rtsp_server.py 使用RTSP服务器流式传输H264和H265编码视频和音频的示例程序
  • 校园管理系统|基于SpringBoot和Vue的校园管理系统(源码+数据库+文档)