@Transactional的坑

@Transactional 是 Spring 框架中用于管理事务的注解,虽然它能极大简化事务管理,但在使用过程中也存在一些容易被忽略的 “坑”

  1. 注解失效问题
    1.1 方法非 public
    @Transactional 注解只能应用在 public 方法上,若用于 private、protected 或默认访问权限的方法,注解将失效。因为 Spring 的 AOP 代理是基于 Java 的访问控制机制,非 public 方法无法被代理增强。
    java
    class Service {
    // 此注解无效
    @Transactional
    private void privateMethod() {
    // 业务逻辑
    }
    }
    1.2 同类方法调用
    在同一个类中,一个方法调用另一个带有 @Transactional 注解的方法,注解会失效。这是因为 Spring 的事务管理是基于 AOP 代理实现的,同类方法调用不会经过代理对象,从而无法触发事务管理逻辑。
    java
    class Service {
    public void outerMethod() {
    innerMethod();
    }

    @Transactional
    public void innerMethod() {
    // 业务逻辑
    }
    }
    1.3 异常未被捕获或异常类型不匹配
    @Transactional 默认只对 RuntimeException 及其子类和 Error 进行回滚。如果抛出的异常不是 RuntimeException 或 Error,且没有指定其他需要回滚的异常类型,事务将不会回滚。
    java
    @Service
    public class UserService {
    @Transactional
    public void updateUser() throws Exception {
    // 业务逻辑
    throw new Exception("自定义异常"); // 不会触发回滚
    }
    }
    可通过 rollbackFor 属性指定需要回滚的异常类型:
    java
    @Transactional(rollbackFor = Exception.class)
    public void updateUser() throws Exception {
    // 业务逻辑
    throw new Exception("自定义异常"); // 会触发回滚
    }

  2. 事务传播行为问题
    2.1 传播行为理解错误
    @Transactional 注解有多种事务传播行为,如 PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS 等。
    PROPAGATION_REQUIRED 是 @Transactional 注解的默认事务传播行为。当一个带有 PROPAGATION_REQUIRED 传播行为的方法被调用时,如果当前存在一个事务,那么该方法会加入到这个事务中执行;如果当前没有事务,那么会创建一个新的事务来执行该方法。
    PROPAGATION_SUPPORTS 表示如果当前存在一个事务,那么该方法会加入到这个事务中执行;如果当前没有事务,那么该方法会以非事务的方式执行。适用于一些既可以在事务中执行,也可以不在事务中执行的方法

java
@Transactional(propagation = Propagation.SUPPORTS)
public void someMethod() {
// 业务逻辑
}
2.2 嵌套事务问题
在嵌套事务中,不同的传播行为会影响事务的提交和回滚。例如,使用 PROPAGATION_NESTED 时,内层事务的回滚可能不会影响外层事务,但如果内层事务抛出异常且未被捕获,可能导致外层事务也回滚。

  1. 数据库隔离级别问题
    3.1 隔离级别不匹配
    @Transactional 注解可以指定数据库隔离级别,如 ISOLATION_READ_COMMITTED、ISOLATION_SERIALIZABLE 等。如果指定的隔离级别与数据库默认隔离级别不匹配,可能会导致性能问题或数据不一致。例如,使用 ISOLATION_SERIALIZABLE 会导致并发性能大幅下降。
    java
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void someMethod() {
    // 业务逻辑
    }
    3.2 不同数据库隔离级别差异
    不同数据库对隔离级别的支持和实现可能存在差异,如 MySQL 和 Oracle 对某些隔离级别的处理方式不同。在使用时需要考虑数据库的特性,避免出现兼容性问题。

  2. 性能问题
    4.1 事务范围过大
    如果事务方法包含大量的业务逻辑,尤其是包含一些耗时操作(如网络请求、文件读写等),会导致事务持有数据库连接的时间过长,降低数据库的并发性能,甚至可能引发死锁。
    java
    @Transactional
    public void longRunningMethod() {
    // 大量业务逻辑和耗时操作
    }
    4.2 频繁开启事务
    在循环中频繁使用 @Transactional 注解开启事务,会增加事务管理的开销,影响性能。应尽量减少不必要的事务开启和提交操作。
    java
    @Service
    public class BatchService {
    @Transactional
    public void batchProcess() {
    for (int i = 0; i < 1000; i++) {
    // 业务逻辑
    }
    }
    }

  3. 多数据源问题
    在使用多数据源的情况下,@Transactional 注解需要与相应的数据源事务管理器配合使用。如果配置不当,可能导致事务管理混乱,无法正确管理不同数据源的事务。
    java
    @Service
    public class MultiDataSourceService {
    @Autowired
    @Qualifier("dataSource1TransactionManager")
    private PlatformTransactionManager transactionManager1;

    @Autowired
    @Qualifier("dataSource2TransactionManager")
    private PlatformTransactionManager transactionManager2;

    // 需要正确配置事务管理器
    @Transactional(transactionManager = "dataSource1TransactionManager")
    public void someMethod() {
    // 业务逻辑
    }
    }

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容