一、事务基础概念
事务的ACID特性:
- 原子性(Atomicity):操作要么全部成功,要么全部失败
- 一致性(Consistency):数据在事务前后保持合法状态
- 隔离性(Isolation):多个事务并发互不干扰
- 持久性(Durability):事务提交后数据永久保存
二、Spring Boot事务实战
1. 环境准备
java
// Maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2. 实体类定义
java
@Entity
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String accountNumber;
private BigDecimal balance;
// 省略getter/setter
}
@Entity
public class TransferLog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String fromAccount;
private String toAccount;
private BigDecimal amount;
// 省略getter/setter
}
3. Service层事务控制
java
@Service
public class BankService {
@Autowired
private AccountRepository accountRepository;
@Autowired
private TransferLogRepository transferLogRepository;
// 核心事务方法
@Transactional(rollbackFor = Exception.class)
public void transferMoney(String fromAccNum, String toAccNum, BigDecimal amount) {
// 1. 扣减转出账户
Account fromAccount = accountRepository.findByAccountNumber(fromAccNum);
fromAccount.setBalance(fromAccount.getBalance().subtract(amount));
accountRepository.save(fromAccount);
// 模拟异常(测试事务回滚)
if(amount.compareTo(BigDecimal.ZERO) < 0) {
throw new RuntimeException("转账金额不能为负数");
}
// 2. 增加转入账户
Account toAccount = accountRepository.findByAccountNumber(toAccNum);
toAccount.setBalance(toAccount.getBalance().add(amount));
accountRepository.save(toAccount);
// 3. 记录转账日志
TransferLog log = new TransferLog();
log.setFromAccount(fromAccNum);
log.setToAccount(toAccNum);
log.setAmount(amount);
transferLogRepository.save(log);
}
}
三、关键注解说明
@Transactional 参数解析:
java
@Transactional(
isolation = Isolation.DEFAULT, // 事务隔离级别
propagation = Propagation.REQUIRED, // 传播行为
rollbackFor = Exception.class, // 指定回滚的异常类型
timeout = 30 // 事务超时时间(秒)
)
四、常见事务失效场景
- 非public方法 :
@Transactional
只能用于public方法 - 自调用问题:同一个类中方法A调用方法B(B有事务注解),事务不生效
- 异常被捕获:事务方法内捕获异常未重新抛出
- 错误异常类型 :默认只回滚RuntimeException,需通过
rollbackFor
指定
五、事务传播机制示例
java
// 嵌套事务示例
@Transactional(propagation = Propagation.REQUIRED)
public void parentMethod() {
// 主事务逻辑
childMethod(); // 嵌套子事务
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void childMethod() {
// 独立事务执行
// 即使外层事务回滚,此方法仍会提交
}
六、事务验证测试
java
@SpringBootTest
class TransactionTest {
@Autowired
private BankService bankService;
@Test
void testTransferSuccess() {
// 正常转账测试
bankService.transferMoney("A123", "B456", new BigDecimal("100.00"));
// 验证账户余额和日志记录
}
@Test
void testTransferRollback() {
// 测试异常回滚
assertThrows(RuntimeException.class, () -> {
bankService.transferMoney("A123", "B456", new BigDecimal("-100.00"));
});
// 验证数据未修改
}
}
最佳实践建议:
- 事务方法尽量放在Service层
- 明确指定
rollbackFor
属性 - 避免长事务(复杂操作拆分为多个小事务)
- 结合
@Transactional
与数据库约束保证数据一致性
扩展学习:
- Spring官方文档:Transactions
- 分布式事务解决方案:Seata、XA协议
- 事务隔离级别深度解析(脏读/幻读/不可重复读)