SpringBoot框架提供的事务管理功能极大地简化了事务处理,使得开发者能够更加专注于业务逻辑的实现,而不是事务处理的细节。支持两种事务管理方式:编程式事务管理和声明式事务管理
一,事务管理器
SpringBoot使用事务管理器来管理事务。顶级接口为PlatformTransactionManager,常用实现类有 DataSourceTransactionManager(用于 JDBC 数据源的事务管理)和 JtaTransactionManager(用于分布式事务管理)
二,事务的属性
1.事务传播行为(Transaction Propagation)
事务传播行为定义了在一个事务方法被调用时,如何管理事务。常见的传播行为如下:
传播行为 | 描述 |
---|---|
REQUIRED | 支持当前事务,如果不存在就新建一个 |
SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务的方式执行 |
MANDATORY | 必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常 |
REQUIRES_NEW | 开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起 |
NOT_SUPPORTED | 以非事务方式运行,如果有事务存在,挂起当前事务 |
NEVER | 以非事务方式运行,如果有事务存在,抛出异常 |
NESTED | 如果当前正有一个事务在进行中,则该方法应当运行在一个嵌入式事务中。被套嵌的事务可以独立于外层事务进行提交和回滚。如果外层事务不存在,行为就像REQUIRE一样 |
2.事务的隔离级别(Transaction Isolation)
事务隔离级别定义了事务之间的隔离程度,以防止并发事务之间的干扰。常见的隔离级别如下:
隔离级别 | 描述 |
---|---|
DEFAULT | 默认,与数据库保持一致 |
READ_UNCOMMITTED | 可能会出现脏读、不可重复读、幻读 |
READ_COMMITTED | 可能会出现不可重复、幻读 |
REPEATABLE_READ (MySQL默认级别) | 可能会出现幻读 |
SERIALIZABLE | 不会出现并发事务的三大问题 |
3.事务超时(Transaction Timeout)
事务超时是指事务在指定时间内未能完成时会被自动回滚。默认情况下,事务没有超时限制
注意:最后一条DML语句之后的代码执行时间不被计入超时时间
4. 只读事务(Read-Only Transaction)
事务执行过程中只允许DQL语句执行,DML语句均不可执行。设置为true可启动Spring优化策略,提高SQL语句执行效率
5.事务回滚
指定哪些异常需要触发事务回滚
三,声明式事务管理
声明式事务管理则是通过配置来管理事务,开发者可以通过注解或XML配置来定义事务的边界和属性,而无需在代码中显式地编写事务管理的代码。这种方式大大减少了代码量,提高了可维护性。下面介绍@Transactional注解实现事务
1.@Transactional注解
@Transactional是Spring提供的主要注解,用于标识一个方法或类需要事务管理
属性 | 说明 |
---|---|
propagation | 事务的传播行为,默认值为PROPAGATION_REQUIRED |
isolation | 事务的隔离级别,默认值为ISOLATION_DEFAULT |
timeout | 事务的超时时间默认值为-1,表示永不超时 |
readOnly | 是否只读事务,默认值为false |
rollbackFor | 指定哪些异常需要触发事务回滚 |
noRollbackFor | 指定哪些异常不触发事务回滚 |
transactionManager | 用于指定使用的事务管理器,""表示使用默认的事务管理器 |
2.代码实现
下列save方法可保证 saveA和saveB()两个DML操作同成功同失败
@Transactional(rollbackFor = Exception.class)
public void save() {
saveA();// 数据库操作
saveB();// 数据库操作
}
3.Spring事务常见失效场景
(1)@Transactional定义的方法访问修饰符不是public
(2)@Transactional定义的类没有被Spring容器管理
(3)业务代码中异常被捕获但未抛出
(4)同一类内的方法直接调用(可使用自注入,使用bean调用方法解决失效)
(5)没有配置事务管理器
(6)事务传播性配置错误
(7)rollbackFor属性配置不当
(8)数据库不支持事务
(9)创建新线程并在新线程中执行数据库操作
四,编程式事务管理
编程式事务管理允许开发者通过编程的方式来控制事务的边界,即何时开始事务、何时提交事务或回滚事务。这种方式提供了极大的灵活性,但同时也增加了代码的复杂度
1.核心接口和类如下:
核心接口 | 作用 |
---|---|
PlatformTranscationManager | Spring事务管理的核心接口,提供了获取事务、提交事务和回滚事务的方法 |
DataSourceTransactionManager | PlatformTranscationManager的实现类,用于 JDBC 数据源的事务管理 |
JtaTransactionManager | PlatformTranscationManager的实现类,用于分布式事务管理 |
TransactionDefinition | 定义了事务的各种属性,如传播行为、隔离级别、超时值等 |
TransactionStatus | 表示事务的状态,包含了事务是否已开始、是否已标记回滚等信息 |
2.多线程事务控制代码实现
下列saveAll方法可以使所有线程中saveDemo()方法同成功同失败
@Service
public class DemoService {
@Autowired
ThreadPoolTaskExecutor threadPool;
@Autowired
DataSourceTransactionManager dsTxManager;
public void saveAll(List<Demo> demos) {
final CountDownLatch latch = new CountDownLatch(demos.size());
AtomicBoolean isRollBack = new AtomicBoolean(false);
for (Demo demo : demos) {
execute(demo, latch, isRollBack);
}
}
public void execute(Demo demo, CountDownLatch latch, AtomicBoolean isRollBack) {
threadPool.execute(() -> {
// 开启事务
TransactionStatus txStatus = dsTxManager.getTransaction(new DefaultTransactionDefinition());
try {
// 数据库操作
saveDemo(demo);
} catch (Exception e) {
// 某个线程发生异常则将回滚标志置为true
isRollBack.set(true);
e.printStackTrace();
} finally {
latch.countDown();
}
// 所有线程都会阻塞等待,直至latch值为0
latch.await();
if (isRollBack.get()) {
// 事务回滚
dsTxManager.rollback(txStatus);
} else {
// 事务提交
dsTxManager.commit(txStatus);
}
});
}
}