在线工具站
- 推荐一个程序员在线工具站:程序员常用工具(http://cxytools.com),有时间戳、JSON格式化、文本对比、HASH生成、UUID生成等常用工具,效率加倍嘎嘎好用。
程序员资料站
- 推荐一个程序员编程资料站:程序员的成长之路(http://cxyroad.com),收录了一些列的技术教程、各大面试专题,还有常用开发工具的教程。
小报童专栏精选Top100
- 推荐一个小报童专栏导航站:小报童精选Top100(http://xbt100.top),收录了生财有术项目精选、AI海外赚钱、纯银的产品分析等专栏,陆续会收录更多的专栏,欢迎体验~
在Java企业级开发中,Spring框架提供的@Transactional
注解是我们实现事务管理的一个重要工具。
事务管理确保了一系列操作要么全部成功,要么全部失败,从而保持数据的一致性和完整性。
然而,在实际使用@Transactional
时,经常会遇到事务穿透性和rollbackFor参数的相关问题。
一、事务的基本概念
1. 什么是事务
事务(Transaction)是指一组操作的集合,这些操作要么全部成功,要么全部失败,是一个不可分割的工作单位。事务具有以下四个特性(ACID):
- 原子性(Atomicity): 事务中的所有操作要么全部完成,要么全部不完成。
- 一致性(Consistency): 事务完成后,数据库从一个一致性状态转移到另一个一致性状态。
- 隔离性(Isolation): 并发执行的事务之间彼此隔离,一个事务的执行不能被其他事务干扰。
- 持久性(Durability): 一旦事务提交,其结果在数据库中是永久性的,即使系统崩溃也不会丢失。
2. Spring中的事务管理
Spring框架通过@Transactional
注解提供了声明式事务管理。通过在方法上使用该注解,可以让Spring自动管理该方法的事务。
@Service
public class MyService {@Transactionalpublic void performTransaction() {// 事务操作}
}
二、事务在不同方法间的穿透性
1. 什么是事务穿透性
事务穿透性指的是在一个事务方法内部调用另一个事务方法时,事务是如何传播和管理的。Spring提供了多种事务传播行为(Propagation),用于控制事务的传播方式。
2. 事务传播行为类型
Spring定义了七种事务传播行为,常用的有以下几种:
- REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则将当前事务挂起。
- NESTED: 如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则与REQUIRED相同。
@Service
public class MyService {@Transactional(propagation = Propagation.REQUIRED)public void methodA() {// 操作AmethodB();// 操作B}@Transactional(propagation = Propagation.REQUIRES_NEW)public void methodB() {// 操作C}
}
在上面的例子中,methodA
使用了REQUIRED
传播行为,而methodB
使用了REQUIRES_NEW
传播行为。当methodA
调用methodB
时,methodA
的事务会被挂起,methodB
会在一个新的事务中执行。
3. 事务传播行为的应用场景
- REQUIRED: 适用于大多数情况,确保操作在同一个事务中执行。
- REQUIRES_NEW: 适用于需要在当前事务外执行的操作,例如记录日志或发送通知。
- NESTED: 适用于需要嵌套事务的情况,例如在一个事务内部执行一个子事务,并希望子事务失败时不会影响父事务的提交。
三、rollbackFor参数的应用
1. 什么是rollbackFor参数
rollbackFor
参数用于指定哪些异常会触发事务回滚。默认情况下,Spring只会在遇到未检查异常(RuntimeException及其子类)时回滚事务,对于已检查异常(Exception及其子类)则不会回滚事务。
2. rollbackFor参数的使用
通过rollbackFor
参数,我们可以指定需要回滚事务的异常类型。例如:
@Service
public class MyService {@Transactional(rollbackFor = Exception.class)public void performTransaction() throws Exception {// 操作Aif (someCondition) {throw new Exception("需要回滚的异常");}// 操作B}
}
在上面的例子中,performTransaction
方法指定了rollbackFor = Exception.class
,意味着当抛出Exception
时会回滚事务。
3. rollbackFor参数的应用场景
rollbackFor
参数适用于以下场景:
- 业务逻辑异常: 例如,某些业务规则未被满足时需要回滚事务。
- 第三方服务异常: 例如,调用外部API失败时需要回滚事务。
- 数据校验异常: 例如,数据格式不正确或不符合业务要求时需要回滚事务。
四、实例分析
1. 案例背景
假设我们有一个银行转账系统,需要实现从一个账户转账到另一个账户的功能。我们需要保证转账操作的原子性,即要么全部成功,要么全部失败。
2. 代码实现
@Service
public class BankService {@Autowiredprivate AccountRepository accountRepository;@Transactionalpublic void transfer(Long fromAccountId, Long toAccountId, BigDecimal amount) throws Exception {// 减少付款账户的余额Account fromAccount = accountRepository.findById(fromAccountId).orElseThrow();fromAccount.setBalance(fromAccount.getBalance().subtract(amount));accountRepository.save(fromAccount);// 增加收款账户的余额addAmountToAccount(toAccountId, amount);}@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)public void addAmountToAccount(Long accountId, BigDecimal amount) throws Exception {// 增加收款账户的余额Account toAccount = accountRepository.findById(accountId).orElseThrow();toAccount.setBalance(toAccount.getBalance().add(amount));accountRepository.save(toAccount);// 模拟异常if (amount.compareTo(BigDecimal.ZERO) < 0) {throw new Exception("无效的转账金额");}}
}
在这个例子中,transfer
方法使用了REQUIRED
传播行为,而addAmountToAccount
方法使用了REQUIRES_NEW
传播行为并指定了rollbackFor = Exception.class
。当transfer
方法调用addAmountToAccount
方法时,如果addAmountToAccount
方法抛出异常,则该方法的事务会回滚,但transfer
方法的事务不会回滚,从而实现了事务的独立性和灵活性。
五、总结
本文深入解析了Java中@Transactional
注解在不同方法间的穿透性及rollbackFor
参数的应用。
通过理解事务传播行为,我们可以更好地控制事务的传播方式,实现复杂的事务管理逻辑。
同时,通过rollbackFor
参数,我们可以指定哪些异常会触发事务回滚,从而确保数据的一致性和完整性。
在实际开发中,合理应用这些知识,可以有效提升应用的稳定性和可靠性。