目录
spring中事务分为声明式事务和编程式事务,本文主要介绍声明式事务
一、声明式事务@Transactional参数
二、事务传播机制
- REQUIRED:Spring默认的事务传播机制。支持当前事务;如果不存在事务,则创建一个新的事务。
- REQUIRES_NEW:创建一个新事务,如果当前存在事务,则暂停当前事务。
- MANDATORY(强制的):仅支持当前事务;如果当前事务不存在,则抛出异常。
- NESTED(嵌套):如果存在当前事务,则在该事务中嵌套执行。同时将在这段逻辑事务开始处标记一个保存点,当这个逻辑事务抛出异常回滚时,那么事务将跳转到保存点,从而不影响嵌套事务的外部。当前事务不存在时,同REQUIRED。
- NEVER:非事务执行,如果存在事务,则抛出异常。
- SUPPORTS:支持当前事务,如果不存在则以非事务方式执行。
- NOT_SUPPORTED:以非事务方式执行,如果当前事务存在,则挂起当前事务。
三、事务隔离级别
- Read Uncommitted(读未提交)
- Read Committed(读已提交)
- Repeatable Read(可重复读)(默认)
- Serializable(可串行化)
四、Spring事务未生效场景
1、抛出事务不支持的异常
原理:
Spring事务默认支持RuntimeException
异常,抛出的异常为RuntimeException异常及其子类异常事务均可生效,而我们日常常见的异常基本都继承自RuntimeException,所以无需指定异常类型事务也能生效。但若手动抛出Exception异常,而Exception是RuntimeException的父类,会导致事务不生效。
解决方案:
1.指定Spring事务异常捕获类型
@Transactional(rollbackFor = Exception.class)
2.抛出Spring事务支持的异常类型
throw new RuntimeException("手动抛出运行时异常");
2、使用了try catch
原理:
异常被try catch块捕获,导致事务失效
解决方案:
在catch中抛出Spring事务支持的异常。
3、添加事务的方法必须是public,并且不能带有static、final关键字
4、类未被Spring管理
原理:
Spring实现对象的动态代理,首先这个对象要交由Spring管理。
解决方案:
将类交由Spring管理,可添加@Service注解,或使用其他能够注册成Spring Bean的注解或方法。
5、数据表不支持事务
原理:
Spring事务基于数据库事务实现,有些数据表本身不支持事务,如MySql的MyISAM引擎,事务自然不生效。
解决方案:
将数据表改用支持事务的引擎,如MySql的InnoDB引擎。
6、Spring事务传播级别设置为不支持事务
原理:
@Transactional(propagation = Propagation.NOT_SUPPORTED) 不支持事务,若存在事务则挂起
@Transactional(propagation = Propagation.NEVER) 不使用事务,若存在事务则抛异常
解决方案:
使用Spring默认的传播级别(PROPAGATION_REQUIRED),或其他支持事务的传播级别。
7、未开启事务
解决方案:
@EnableTransactionManagement开启事务,Spring boot已自动装配,无需显示使用此注解。
8、多线程调用
@Transactional注解只能对当前线程的事务进行管理,而对于多个线程之间的事务协调和管理,需要使用分布式事务进行控制。可以使用Spring Cloud提供的分布式事务管理器,如Seata、TCC等,来协调多个线程之间的事务,确保事务的一致性。