Spring Boot事务管理详解(附银行转账案例)

一、事务基础概念

事务的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                     // 事务超时时间(秒)
)

四、常见事务失效场景

  1. 非public方法@Transactional只能用于public方法
  2. 自调用问题:同一个类中方法A调用方法B(B有事务注解),事务不生效
  3. 异常被捕获:事务方法内捕获异常未重新抛出
  4. 错误异常类型 :默认只回滚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"));
        });
        // 验证数据未修改
    }
}

最佳实践建议

  1. 事务方法尽量放在Service层
  2. 明确指定rollbackFor属性
  3. 避免长事务(复杂操作拆分为多个小事务)
  4. 结合@Transactional与数据库约束保证数据一致性

扩展学习

  • Spring官方文档:Transactions
  • 分布式事务解决方案:Seata、XA协议
  • 事务隔离级别深度解析(脏读/幻读/不可重复读)
相关推荐
AD钙奶-lalala9 分钟前
Mac OS上搭建 http server
java
老马啸西风15 分钟前
v0.29.2 敏感词性能优化之基本类型拆箱、装箱的进一步优化的尝试
性能优化·开源·nlp·github·敏感词
伴杯猫3 小时前
【ESP32-IDF】基础外设开发2:系统中断矩阵
c语言·单片机·嵌入式硬件·mcu·物联网·github
皮皮林5514 小时前
SpringBoot 全局/局部双模式 Gzip 压缩实战:14MB GeoJSON 秒变 3MB
java·spring boot
weixin_456904274 小时前
Spring Boot 用户管理系统
java·spring boot·后端
趁你还年轻_4 小时前
异步编程CompletionService
java
DKPT4 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
sibylyue4 小时前
Guava中常用的工具类
java·guava
奔跑吧邓邓子4 小时前
【Java实战㉞】从0到1:Spring Boot Web开发与接口设计实战
java·spring boot·实战·web开发·接口设计
专注API从业者5 小时前
Python/Java 代码示例:手把手教程调用 1688 API 获取商品详情实时数据
java·linux·数据库·python