Spring事务管理(数据一致性)

1. 基础/核心

1.1、Spring 支持哪两种事务管理方式?(编程式事务、声明式事务)

  • 编程式事务 :使用 TransactionTemplate 或 PlatformTransactionManager 手动编写代码控制事务的提交与回滚。灵活度高,但代码侵入性强。
  • 声明式事务 :基于 AOP(面向切面编程) ,通过 @Transactional 注解或 XML 配置将事务管理与业务代码分离。代码无侵入,最常用。

1.2、@Transactional 注解有哪些常用的属性?

  • propagation :事务传播行为(默认 REQUIRED)。
  • isolation :事务隔离级别(默认 DEFAULT)。
  • timeout:事务超时时间(单位:秒)。
  • readOnly:只读事务。优化只读操作的性能,限制事务内的写操作。
  • rollbackFor :指定哪些异常触发回滚(Spring 默认仅在遇到 RuntimeException 和 Error 时回滚)。
  • noRollbackFor:指定哪些异常不触发回滚。

2. 高频/进阶

2.1、【必考】 Spring 事务的传播行为(Propagation)有哪些?

Spring 共定义了 7 种传播行为,用于解决业务方法互相调用时,事务如何流转的问题:

  • REQUIRED(默认):如果当前存在事务,则加入该事务;如果不存在,则创建一个新事务。外层与内层方法共用同一个事务,任何地方报错全盘回滚。
  • REQUIRES_NEW :创建一个新事务。如果当前存在事务,则将当前事务挂起。内层新事务的提交或回滚独立于外层事务,互不影响。
  • NESTED :如果当前存在事务,则在嵌套事务内执行(利用数据库的 Savepoint 保存点)。内层事务回滚会跳回保存点,不影响外层事务提交;但外层事务回滚,内层嵌套事务会随之回滚。
  • 其他 4 种 :SUPPORTS(有则用,无则无)、NOT_SUPPORTED(以非事务运行,有则挂起)、MANDATORY(必须在事务中运行,否则报错)、NEVER(不能在事务中运行,否则报错)。

2.2、Spring 事务的隔离级别有哪些?它们和数据库的隔离级别有什么关系?

Spring 的 Isolation 枚举定义了 5 个隔离级别:

  • DEFAULT :使用底层数据库默认的隔离级别(MySQL 默认为 RR,Oracle 默认为 RC)。
  • READ_UNCOMMITTED(读未提交):引发脏读、不可重复读、幻读。
  • READ_COMMITTED(读已提交):解决脏读,引发不可重复读、幻读。
  • REPEATABLE_READ(可重复读):解决脏读、不可重复读,引发幻读。
  • SERIALIZABLE(串行化):解决所有并发问题,性能最低。
  • 关系 :Spring 事务隔离级别是对底层数据库能力的封装。如果数据库(如底层未开启某隔离级别)不支持,Spring 配置的隔离级别将无法生效。

3. 源码/深度

3.1、【必考】 Spring 事务在什么情况下会失效?

  • 内部方法自调用 :在同一个类中,A 方法(无事务)通过 this.B() 调用本类带 @Transactional 的 B 方法,此时调用不走代理对象,事务失效。
  • 修饰非 public 方法 :Spring 默认要求 @Transactional 只能应用在 public 方法上。修饰 private、protected 或 package-private 方法时,AOP 代理会直接忽略。
  • 异常被内部 try-catch 吞掉 :业务代码自行捕获了异常却没有重新抛出,或者抛出了非 RuntimeException(且未配置 rollbackFor = Exception.class),导致 Spring 无法感知异常,事务正常提交。
  • 数据库引擎本身不支持事务 :如 MySQL 使用了 MyISAM 存储引擎,而非 InnoDB。
  • 目标类未被 Spring 管理 :类上漏掉了 @Service 或 @Component 注解,该类不会生成 Spring Bean 及其代理对象。

3.2、Spring 事务的底层原理是什么?它是如何利用 AOP 和 ThreadLocal 实现的?

  • AOP 拦截 :Spring 在初始化 Bean 时,若发现方法上有 @Transactional,会通过 JDK 动态代理或 CGLIB 动生成代理对象。调用该方法时,会被 TransactionInterceptor 拦截。
  • 连接绑定与 ThreadLocal :拦截器通过 PlatformTransactionManager 获取数据库连接。为了确保在同一个事务周期内(例如 Service 调多个 DAO),所有数据库操作都使用同一个数据库连接 ,Spring 利用 TransactionSynchronizationManager 内部的 ThreadLocal<Map<Object, Object>> 将当前数据库连接(Connection)与当前线程进行绑定。
  • 增强逻辑 :代理对象在目标业务方法执行前开启事务(autoCommit = false);执行业务方法(各个 DAO 从 ThreadLocal 拿同一个连接执行 SQL);若成功则提交(commit),若抛出指定异常则回滚(rollback),最后将连接从 ThreadLocal 中清除并关闭。
相关推荐
涛思数据(TDengine)2 分钟前
TDengine IDMP 2.0.2 发布:元素关系可视化、数据建模与联邦查询三大升级
大数据·数据库·人工智能·时序数据库·tdengine·工业互联网·工业ai
小米里的大麦3 分钟前
17 MySQL 视图
数据库·mysql
ss2738 分钟前
PG实战笔记 | 07 PostgreSQL常见编译项及其作用
数据库·笔记·postgresql
丨白色风车丨22 分钟前
LangChain 1.0 核心用法速查:创建模型、创建 Agent、调用
数据库·langchain
临床数据科学和人工智能兴趣组24 分钟前
正则表达式的基础语法的常用字符类
数据库·r语言·r语言-4.2.1·临床研究·临床试验
鱼很腾apoc27 分钟前
【MySQL】 第2期 查询与函数系统详解:从基础 CRUD 到复合多表查询
linux·数据库·学习·mysql·dml
萧瑟余晖1 小时前
Spring Web综合实战与性能调优详解
java·spring
点纭1 小时前
spring ai1.0实战:ChatClient(2)
java·后端·spring
前端 贾公子1 小时前
LangGraph == 图的状态(State)管理 (下)
运维·服务器·数据库
小马过河R1 小时前
EdgeOne深度解析:从原理、适用场景到COS接入的技术逻辑
java·开发语言·前端·spring·cos