自学内容网 自学内容网

Java + Spring Boot + MyBatis 事务注解 @Transactional 使用规范说明

在Spring Boot + MyBatis项目中,并非每个Service方法都需要添加@Transactional注解。是否添加该注解取决于具体业务场景和操作需求。以下是详细分析:


一、必须使用@Transactional的场景

  1. 多数据库操作需原子性
    当方法内包含多个数据库写操作(如多个INSERT/UPDATE/DELETE),且需要保证这些操作要么全部成功,要么全部失败时,必须使用事务。
    示例:转账操作(扣款+加款)

    java

    复制

    下载

    @Transactional
    public void transferMoney(Long from, Long to, BigDecimal amount) {
        accountMapper.deduct(from, amount);
        // 此处若发生异常,扣款操作会回滚
        accountMapper.add(to, amount);
    }
  2. 跨Service方法调用
    如果Service方法A调用了其他Service方法B和C,且这些操作需要作为一个整体,则应在A上添加事务注解。


二、无需使用@Transactional的场景

  1. 单一查询操作
    纯查询方法(SELECT)通常不需要事务。但若要求强一致性(如避免脏读),可添加只读事务:

    java

    复制

    下载

    @Transactional(readOnly = true) // 优化性能,避免写锁
    public User getUserById(Long id) {
        return userMapper.selectById(id);
    }
  2. 单一写操作
    如果方法仅含一个写操作(如单个INSERT),数据库本身已保证原子性,可不加事务。

    注意:某些场景仍需事务(如需要回滚后续非DB操作)。

  3. 非数据库操作
    方法内无任何数据库操作(如计算逻辑、调用外部API)时,不需要事务。


三、最佳实践建议

  1. 在Service层添加注解
    事务注解应加在Service层而非Mapper层,确保业务逻辑完整性。

  2. 显式配置事务属性
    明确指定传播行为、隔离级别、超时时间等:

    java

    复制

    下载

    @Transactional(
        propagation = Propagation.REQUIRED, // 默认:当前有事务则加入,无则新建
        isolation = Isolation.DEFAULT,       // 使用数据库默认隔离级别
        timeout = 30,                       // 超时时间(秒)
        rollbackFor = Exception.class       // 指定回滚的异常类型
    )
    public void businessMethod() { ... }
  3. 避免事务滥用
    不必要的事务会增加性能开销(如获取/释放连接、事务同步等)。

  4. 只读查询显式标记
    查询方法建议添加@Transactional(readOnly = true),帮助数据库优化执行。


四、常见误区

  • 误区:所有方法都加事务更“安全”。
    纠正:过度使用事务可能导致死锁、性能下降、连接池耗尽等问题。

  • 误区:事务能解决所有一致性需求。
    纠正:分布式场景需结合分布式事务(如Seata)或最终一致性方案。


五、总结

场景是否需要@Transactional
多数据库写操作✅ 必须
跨方法组合操作✅ 必须
单一查询(强一致性要求)⚠️ 建议只读事务
单一写操作(仅1次INSERT/UPDATE)❌ 通常不需要
非数据库操作❌ 不需要

核心原则

根据业务逻辑的原子性需求决定是否使用事务,而非盲目添加。始终优先考虑性能与场景的匹配性。


原文地址:https://blog.csdn.net/BillKu/article/details/148581760

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!