Java:事务管理全景梳理/解决业务系统数据一致性问题

事务核心目标:保证一组数据库操作,要么全部成功,要么全部失败回滚。Java事务分为:JDBC原生事务、JTA分布式事务、Spring声明式/编程式事务,包含传播行为、隔离级别、回滚规则、失效场景,全部以表格结构化整理。
本质:数据库原生有事务能力,但裸用 JDBC 写事务代码极其繁琐;Java 事务管理(尤其 Spring 事务)是对数据库事务的高层封装,解决业务系统数据一致性问题
Java事务管理是对数据库事务能力的高层封装,核心是保障一组数据库操作原子执行,要么全部成功提交,要么失败整体回滚,维护数据ACID特性。原生JDBC需手动编写提交、回滚样板代码,开发繁琐易出错。Spring事务通过AOP与@Transactional注解简化开发,提供传播行为、隔离级别、异常回滚、超时等能力,自动管理数据库连接资源。区分本地事务与分布式事务,解决方法嵌套调用、并发业务的数据一致性,避免出现扣钱不加账这类脏数据,是业务系统保障数据可靠的基础组件。

一、事务基础概念

ACID四大特性

特性 全称 说明
A Atomicity 原子性 事务内操作不可分割,全部成功或全部回滚
C Consistency 一致性 事务前后业务数据状态合法,由原子+隔离+持久共同保障
I Isolation 隔离性 多个事务并发,互相之间数据不可见,防止脏读、不可重复读、幻读
D Durability 持久性 事务提交后,修改永久落地数据库,宕机不丢失

并发事务3大问题

问题 描述
脏读 A事务读到B事务未提交的数据,如果B回滚,读到脏无效数据
不可重复读 同一事务内,同一行数据两次查询结果不一样,被其他事务提交修改
幻读 同一事务,同样条件查询,前后返回行数变化,其他事务插入/删除数据

数据库隔离级别(MySQL InnoDB)

隔离级别 脏读 不可重复读 幻读 MySQL默认
READ UNCOMMITTED 读未提交 ✅发生 ✅发生 ✅发生 极少使用
READ COMMITTED 读已提交(RC) ❌避免 ✅发生 ✅发生 Oracle默认
REPEATABLE READ 可重复读(RR) ❌避免 ❌避免 ✅(InnoDB MVCC规避) ✅MySQL InnoDB默认
SERIALIZABLE 串行化 ❌避免 ❌避免 ❌避免 性能极低,几乎不用

InnoDB 在 RR级别通过MVCC解决幻读快照读;当前读(select ... for update)会通过临键锁解决幻读。

二、Java 三套事务体系对比

事务体系 适用场景 API入口 是否依赖容器 特点
JDBC原生事务 单库本地事务 Connection 否,纯JDBC 底层原始,手动编码;关闭自动提交setAutoCommit(false)
JTA(Java Transaction API) 分布式多数据源事务 UserTransaction 需要容器(Tomcat/JBoss)或Atomikos等第三方 XA二阶段提交,性能差,开发繁琐
Spring事务 绝大多数业务,单库为主,也可集成JTA @Transactional / TransactionTemplate Spring环境 封装JDBC/JTA,分为编程式、声明式;开发主流

2.1 JDBC原生事务核心代码要点

Connection关键方法:

方法 作用
connection.setAutoCommit(false) 关闭自动提交,开启事务
connection.commit() 手动提交事务
connection.rollback() 回滚事务
connection.setSavepoint() 设置保存点,支持局部回滚

缺陷:每个业务都要写try‑catch‑commit‑rollback样板代码;多数据源无法支持;没有传播行为。

2.2 JTA 分布式事务

JTA:Java规范,定义事务接口;底层实现XA协议2PC

角色:事务管理器TM、资源管理器RM(各个数据库)

对象 作用
javax.transaction.UserTransaction 用户操作事务:begin/commit/rollback
javax.transaction.TransactionManager 底层事务管理器
XAResource 每个数据库资源参与分布式事务接口

缺点:性能损耗大;部分数据库驱动对XA支持一般;现在业务更多用Seata替代JTA。

三、Spring事务两大模式:编程式 vs 声明式

模式 实现方式 核心API 优点 缺点
编程式事务 硬编码写在业务代码 TransactionTemplate / PlatformTransactionManager 细粒度控制,灵活;不受AOP限制 侵入业务代码,重复样板代码
声明式事务 AOP代理,注解@Transactional @Transactional注解 无侵入业务,简洁,开发主流 依赖SpringAOP代理;存在大量失效坑

Spring事务底层依然是封装JDBC Connection或者JTA。

Spring核心事务管理器接口

PlatformTransactionManager 顶层接口

实现类 场景
DataSourceTransactionManager JDBC/MyBatis,单数据源本地事务,最常用
JpaTransactionManager JPA/Hibernate
JtaTransactionManager JTA分布式XA事务

接口方法:

复制代码
// 获取事务状态
TransactionStatus getTransaction(TransactionDefinition definition);
// 提交
void commit(TransactionStatus status);
// 回滚
void rollback(TransactionStatus status);

TransactionDefinition:事务定义信息

包含:传播行为、隔离级别、超时时间、是否只读。

四、Spring 7种事务传播行为(重点)

传播行为:一个已经存在事务的方法,调用另一个带事务的方法,事务如何共用/新建

传播行为 常量名称 说明
REQUIRED PROPAGATION_REQUIRED 默认。有事务就加入当前事务;没有就新建事务。
SUPPORTS PROPAGATION_SUPPORTS 有事务就加入;没有就非事务执行。
MANDATORY PROPAGATION_MANDATORY 必须已有事务,没有则抛异常。
REQUIRES_NEW PROPAGATION_REQUIRES_NEW 总是新建独立事务,挂起外层事务;内层回滚不影响外层。
NOT_SUPPORTED PROPAGATION_NOT_SUPPORTED 挂起当前事务,以非事务运行。
NEVER PROPAGATION_NEVER 禁止存在事务,已有事务直接抛异常。
NESTED PROPAGATION_NESTED 嵌套事务;底层数据库保存点;外层回滚内层跟着回滚;内层回滚不影响外层。仅DataSourceTransactionManager支持。

面试高频区分:REQUIRES_NEW vs NESTED

REQUIRES_NEW:完全独立两个事务;

NESTED:同一个事务,依靠savepoint保存点实现嵌套。

五、@Transactional注解完整属性表

属性 作用 取值说明
propagation 传播行为 Propagation.REQUIRED / REQUIRES_NEW等7种
isolation 隔离级别 Isolation.READ_COMMITTED、REPEATABLE_READ...
timeout 事务超时秒数 默认‑1不超时;超时自动回滚
readOnly 是否只读 true:优化,禁止写操作;不是强制校验,给数据库提示
rollbackFor 指定异常触发回滚 Class数组;rollbackFor = Exception.class
rollbackForClassName 异常全限定名,字符串形式 用于注解配置无法直接引入类
noRollbackFor 指定异常不回滚 发生该异常,事务依然提交
noRollbackForClassName 字符串版本noRollbackFor

⚠️ 默认规则:Spring声明式事务仅对RuntimeException、Error才回滚;普通受检Exception不会回滚! 捕获异常不抛出也不会回滚。

六、Spring事务常见失效场景(高频面试)

失效场景 现象 原因
1.非public方法上加@Transactional 事务不生效 SpringAOP只能拦截public;private/protected/default无法生成代理
2.同类内部方法调用 this.xxx()调用本类注解方法,事务失效 this是原始对象,不走AOP代理对象;AOP只有外部调用代理对象才生效
3.异常被try‑catch捕获,没有抛出 异常吞掉,事务不会回滚 SpringAOP通过捕获方法抛出异常触发回滚;catch住不抛出感知不到异常
4.数据库引擎不支持事务(MyISAM) 完全没有事务能力 MyISAM不支持事务,要InnoDB
5.传播行为配置错误 内层异常外层不回滚或者不开启事务 例如SUPPORTS/NOT_SUPPORTED等
6.多数据源,使用普通DataSourceTransactionManager 只能单库生效,跨库不具备原子性 本地事务只绑定一个Connection,跨库需要分布式事务JTA/Seata
7.多线程环境调用事务方法 子线程无法继承主线程事务 Spring事务绑定ThreadLocal,不同线程ThreadLocal隔离;子线程会新建事务
8.手动设置readOnly=true却做写操作 部分数据库抛异常,部分数据库仅提示 readOnly只是优化hint,不是强制拦截写SQL
9.自己new对象,不用Spring容器获取Bean 注解完全无效 没有被SpringAOP代理,是原生对象

同类调用解决方案:1.注入自身代理;2.拆分到不同Service;3.通过AopContext获取代理对象。

七、Spring事务底层原理

1、Spring启动扫描@Transactional,生成AOP代理对象(JDK动态代理 / CGLIB)

2、调用代理对象方法,进入TransactionInterceptor拦截器

3、TransactionDefinition解析注解配置,交给PlatformTransactionManager

4、从ThreadLocal获取/创建数据库Connection,关闭autoCommit

5、执行业务逻辑;方法抛出异常:执行rollback;正常结束执行commit

6、Connection归还连接池。
关键点:Connection绑定到当前线程ThreadLocal,同一个线程内多个事务方法拿到同一个数据库连接。

关键点 说明
Connection绑定 TransactionSynchronizationManager ThreadLocal保存Connection资源
代理方式 实现接口用JDK动态代理;类无接口使用CGLIB代理
回滚标记 TransactionStatus.setRollbackOnly()标记回滚,即使不抛异常也回滚

手动触发回滚(编程式)

复制代码
TransactionStatus status = TransactionAspectSupport.currentTransactionStatus();
status.setRollbackOnly();

八、本地事务 vs 分布式事务对比

维度 Spring本地事务(DataSourceTransactionManager) 分布式事务(JTA/Seata)
数据库数量 单数据源,一个数据库连接 多个数据库、多个微服务
底层原理 JDBC Connection事务 XA‑2PC / TCC / AT / SAGA
性能 几乎无额外损耗 开销大,AT模式存在undo_log日志
实现难度 简单,@Transactional直接使用 复杂,需要额外组件
数据一致性 强一致性 AT模式最终一致性;XA强一致

企业现状:JTA XA性能差,新项目一般不用;微服务分布式事务主流使用 Seata AT模式

九、最佳实践总结表格

实践 建议
注解位置 @Transactional写在public方法;推荐写在Service层,不要写Controller
回滚配置 业务上建议rollbackFor = Exception.class,避免受检异常不回滚坑
避免同类内部调用 业务拆分不同Service,不要this调用
大事务 尽量缩小事务范围;避免把RPC、大查询放入事务,防止长事务锁表、数据库连接耗尽
多线程 不要在子线程执行数据库事务;子线程无法继承父线程事务
只读查询 查询方法设置readOnly=true,给底层驱动优化提示
异常处理 如果需要catch部分异常,catch后手动设置回滚标记或者抛出异常

常见坑速记

  1. @Transactional不是万能,依赖AOP代理+public+抛出异常;
  2. Spring默认只回滚RuntimeException/Error;
  3. ThreadLocal绑定Connection,跨线程事务失效;
  4. 单库用DataSourceTransactionManager;跨库微服务不要指望@Transactional解决,要用分布式事务方案。
相关推荐
额额额对了1 小时前
Linux 进程管理详解:从概念到实战
java·服务器·前端
evans在进步1 小时前
Spring Boot 启动流程与 @SpringBootApplication 核心原理详解
java·spring boot·后端
许彰午1 小时前
11-rawSql占位符替换
java·低代码·架构
码匠许师傅1 小时前
【C++ 面试真题】聊聊 C++ 的类型特征( type_traits)
java·c++·面试
java1234_小锋1 小时前
Spring框架的创始人开发了一个Java AI智能体框架
java·人工智能·spring
夏天拐跑了西瓜1 小时前
Eureka注册中心——单机与高可用集群搭建
java·spring cloud·微服务·eureka
Caster_Z1 小时前
IntelliJ IDEA 安装 Qoder CN (Formerly Lingma)
java·ide·intellij-idea
前端炒粉1 小时前
fetch+readablestream(Streamable)流式输出
java·服务器·前端
珍珠先生2 小时前
第18章 泛型入门
java