Java-136 深入浅出 MySQL Spring Boot @Transactional 使用指南:事务传播、隔离级别与异常回滚策略
点一下关注吧!!!非常感谢!!持续更新!!!
🚀 AI篇持续更新中!(长期更新)
AI炼丹日志-31- 千呼万唤始出来 GPT-5 发布!“快的模型 + 深度思考模型 + 实时路由”,持续打造实用AI工具指南!📐🤖
💻 Java篇正式开启!(300篇)
目前2025年09月22日更新到:
Java-130 深入浅出 MySQL MyCat 深入解析 核心配置文件 server.xml 使用与优化
MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务正在更新!深入浅出助你打牢基础!
📊 大数据板块已完成多项干货更新(300篇):
包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解
注解参数
在 Transactional 注解中,定义了详细的内容。
value
value注解和transactionManager注解是相互的。
/**
* Alias for {@link #transactionManager}.
* @see #transactionManager
*/
@AliasFor("transactionManager")
String value() default "";
transactionManager
value注解和transactionManager注解是相互的。
@AliasFor("value")
String transactionManager() default "";
propagation
事务的传播类型
Propagation propagation() default Propagation.REQUIRED;
REQUIRED(默认)
- 行为描述:如果当前存在事务,则加入当前的事务;如果没有就会新建一个事务
- 应用场景:最常用的传播行为,适用于大多数业务场景
- 示例:当ServiceA调用ServiceB时,如果ServiceA已开启事务,则ServiceB会加入该事务;否则ServiceB会新建事务
REQUIRES_NEW
- 行为描述:无论当前是否有事务,总是新建一个事务
- 特点:新事务会挂起当前事务(如果存在)
- 应用场景:需要独立于当前事务执行的业务逻辑,如日志记录、审计等
- 示例:支付主流程中需要记录操作日志,即使支付失败也要保留日志记录
SUPPORTS
- 行为描述:支持当前事务,如果没有事务也可以正常执行
- 特点:不会主动开启事务
- 应用场景:查询操作或非核心业务逻辑
- 示例:获取用户信息的服务方法,可以在事务中调用,也可以单独调用
NOT_SUPPORTED
- 行为描述:不支持事务,执行时挂起任何现有的事务
- 特点:以非事务方式执行
- 应用场景:不需要事务支持的操作,如某些性能敏感的批量处理
- 示例:大数据量的报表生成,不需要事务保证
MANDATORY
- 行为描述:必须在一个现有事务中运行,否则会抛出异常
- 特点:强制要求调用方必须开启事务
- 应用场景:必须参与事务的关键业务逻辑
- 示例:资金转账操作必须在一个事务中执行
NEVER
- 行为描述:不允许在事务中运行,否则会抛出异常
- 特点:强制要求无事务环境
- 应用场景:特殊场景下需要确保不在事务中执行的方法
- 示例:某些与事务冲突的特殊操作
NESTED
- 行为描述:如果当前存在事务,则嵌套在该事务中
- 特点:
- 可以设置保存点,部分回滚
- 外层事务回滚会导致内层事务回滚
- 内层事务回滚不会影响外层事务
- 应用场景:复杂业务中需要部分回滚的场景
- 示例:订单处理中的子项处理,某个子项失败只需回滚该子项,不影响其他子项
isolation
设置事务的隔离级别,以控制事务之间的干扰。
Isolation isolation() default Isolation.DEFAULT;
● DEFAULT:使用数据库默认的隔离级别。不同数据库的默认级别不同,例如MySQL默认为REPEATABLE_READ,Oracle默认为READ_COMMITTED,SQL Server默认为READ_COMMITTED。
● READ_UNCOMMITED(读未提交):
- 最低的隔离级别
- 允许读取其他事务未提交的修改(脏读)
- 典型问题场景:
- 事务A修改数据但未提交,事务B读取到未提交数据
- 如果事务A回滚,事务B读取的就是无效数据
- 性能最好但数据一致性最差
● READ_COMMITTED(读已提交):
- 只允许读取已提交的数据
- 解决了脏读问题
- 仍存在的问题:
- 不可重复读:事务内两次读取同一数据可能结果不同
- 幻读:事务执行过程中,其他事务插入了新记录
- 大多数数据库的默认级别
● REPEATABLE_READ(可重复读):
- 保证在事务内多次读取同一数据结果一致
- 解决了不可重复读问题
- 仍存在的问题:
- 幻读:其他事务可能插入新记录
- 实现方式:
- 通常通过多版本并发控制(MVCC)实现
- MySQL的默认隔离级别
● SERIALIZABLE(串行化):
- 最高的隔离级别
- 完全串行化执行事务
- 解决所有并发问题:
- 脏读
- 不可重复读
- 幻读
- 缺点:
- 性能最低
- 可能导致大量锁等待
- 适用场景:
- 需要最高数据一致性的场景
- 金融交易等关键业务
各隔离级别对比表:
隔离级别 | 脏读 | 不可重复读 | 幻读 | 性能 |
---|---|---|---|---|
READ_UNCOMMITED | 可能 | 可能 | 可能 | 最高 |
READ_COMMITTED | 不可能 | 可能 | 可能 | 高 |
REPEATABLE_READ | 不可能 | 不可能 | 可能 | 中 |
SERIALIZABLE | 不可能 | 不可能 | 不可能 | 低 |
timeout
指定事务的超时时间,单位为秒,超过时间事务将被回滚。
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
readOnly
设置事务只读,主要用于查询方法,优化性能。只读事务中不能进行数据更新操作。
boolean readOnly() default false;
rollbackFor
指定哪些异常类型导致事务回滚,默认情况下,RuntimeException 和 Error 会导致回滚,而 checked exception 不会导致回滚。
Class<? extends Throwable>[] rollbackFor() default {};
rollbackForClassName
指定哪些异常类型导致事务回滚,默认情况下,RuntimeException 和 Error 会导致回滚,而 checked exception 不会导致回滚。
String[] rollbackForClassName() default {};
noRollbackFor
noRollbackFor
属性用于指定哪些异常类型不触发事务回滚机制,与 rollbackFor
属性形成互补关系。当方法抛出 noRollbackFor
指定的异常类型或其子类时,事务会继续提交而不会回滚。
主要特点
- 与rollbackFor相反:
rollbackFor
定义需要回滚的异常,而noRollbackFor
定义不需要回滚的异常 - 异常继承性:对指定异常的子类同样有效
- 默认行为:默认情况下,只有RuntimeException和Error会导致回滚
语法格式
@Transactional(noRollbackFor = {IOException.class, SQLTimeoutException.class})
public void someMethod() {...}
典型应用场景
- 业务异常处理:当某些业务异常(如库存不足)需要正常完成事务流程时
- 可恢复异常:如网络超时异常,希望重试而非回滚
- 日志记录异常:记录日志失败的异常不应影响主事务
注意事项
- 如果同时配置了
rollbackFor
和noRollbackFor
,后者优先级更高 - 建议明确指定业务相关的异常类型,而不是依赖默认行为
- 对checked exception需要显式声明才会生效
示例
// 当抛出InventoryException时事务不会回滚
@Transactional(noRollbackFor = InventoryException.class)
public void processOrder(Order order) throws InventoryException {// 业务逻辑if(stock < order.getQuantity()){throw new InventoryException("库存不足");}// 其他操作
}
这个属性在需要精细控制事务行为的场景中特别有用,可以避免不必要的回滚操作影响系统性能或业务逻辑。
Class<? extends Throwable>[] noRollbackFor() default {};
noRollbackForClassName
noRollbackForClassName
是 Spring 事务管理中的一个配置属性,用于指定某些异常类型不会触发事务回滚。这个属性与 rollbackForClassName
的功能正好相反,可以用来定义特定的异常白名单。
详细说明
-
作用机制:
- 当方法抛出
noRollbackForClassName
中指定的异常或其子类时,事务将继续提交而不会回滚 - 适用于业务中那些"可以接受的"异常情况,比如业务校验不通过等预期内的异常
- 当方法抛出
-
配置方式:
@Transactional(noRollbackForClassName = {"com.example.BusinessException", "com.example.ValidationException"})public void someMethod() {// 方法实现}
-
典型应用场景:
- 业务校验失败(如用户输入不合法)
- 预期的业务异常(如账户余额不足)
- 需要记录日志但不需要回滚的异常情况
-
注意事项:
- 需要提供完整的异常类名(包括包路径)
- 对于检查型异常(checked exception)默认不会导致回滚,通常不需要特别配置
- 与
rollbackFor
/rollbackForClassName
配合使用时,后者优先级更高
-
示例对比:
// 配置1:所有异常都回滚,除了BusinessException@Transactional(noRollbackForClassName = "com.example.BusinessException")// 配置2:默认只回滚RuntimeException,额外配置也回滚IOException@Transactional(noRollbackForClassName = "java.io.IOException")
- 替代方案:
在较新版本的 Spring 中,推荐使用noRollbackFor
属性(基于 Class 对象而非字符串),可以获得编译时类型检查的优势:
@Transactional(noRollbackFor = {BusinessException.class, ValidationException.class})
String[] noRollbackForClassName() default {};