您的当前位置:首页正文

java——@Transactional 在哪些情况下会失效?

2024-11-30 来源:个人技术集锦

@Transactional注解失效原因分类

@Transactional注解在Spring框架中用于声明式事务管理,确保数据的一致性和可靠性。然而,在某些情况下,@Transactional注解可能会失效。以下是一些常见的情况及原因:

避免@Transactional注解失效策略

  • 方法是public的。
  • 避免在同一个类中直接调用其他事务方法(可以通过注入自身的方式来解决)。
  • 正确配置事务管理器。
  • 不要在事务方法内部捕获并处理可能导致事务回滚的异常(或者重新抛出一个Spring框架能够识别的异常)。
  • 避免使用final和static修饰事务方法。
  • 确保类被Spring管理。
  • 正确配置事务的传播特性。
  • 使用支持事务的数据库表和存储引擎。
  • 在多线程环境下,确保事务方法在同一个线程中执行。

通过遵循这些原则,可以最大程度地确保@Transactional注解在Spring框架中的正确性和有效性。

底层原码

@Transactional 注解是 Spring 框架中用于声明式事务管理的关键注解。它通过 AOP(面向切面编程)机制在方法调用前后插入事务管理逻辑。要理解 @Transactional 的底层实现,我们需要深入到 Spring 的源代码中。

1. @Transactional 注解

@Transactional 是一个元注解,定义在 org.springframework.transaction.annotation 包下:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    // 定义了各种属性,如传播行为、隔离级别等
    Propagation propagation() default Propagation.REQUIRED;
    Isolation isolation() default Isolation.DEFAULT;
    int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
    boolean readOnly() default false;
    Class<? extends Throwable>[] rollbackFor() default {};
    String[] rollbackForClassName() default {};
    Class<? extends Throwable>[] noRollbackFor() default {};
    String[] noRollbackForClassName() default {};
}

2. TransactionInterceptor 类

@Transactional 注解的实现依赖于 TransactionInterceptor 类,这是一个实现了 MethodInterceptor 接口的拦截器。TransactionInterceptor 负责在方法调用前开启事务,在方法调用后提交或回滚事务。

TransactionInterceptor 的关键方法
  • invoke 方法:这是 MethodInterceptor 接口的核心方法,负责拦截方法调用并处理事务逻辑。
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
    // 获取事务属性
    TransactionAttributeSource tas = getTransactionAttributeSource();
    TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(invocation.getMethod(), invocation.getClass()) : null);
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);

    // 如果没有事务属性,则直接调用目标方法
    if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
        // Standard transaction demarcation with getTransaction and commit/rollback calls.
        TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, invocation);
        Object retVal;
        try {
            // 执行目标方法
            retVal = invocation.proceedWithInvocation();
        }
        catch (Throwable ex) {
            // 处理异常
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        }
        finally {
            cleanupTransactionInfo(txInfo);
        }
        // 提交事务
        commitTransactionAfterReturning(txInfo);
        return retVal;
    }

    // 使用回调方式处理事务
    else {
        // It's a CallbackPreferringPlatformTransactionManager: pass a callback in order to
        // avoid unnecessary intermediate transactions and allow for eager triggering of actual
        // suspension at the head of the chain.
        return ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
                new TransactionCallback<Object>() {
                    @Override
                    public Object doInTransaction(TransactionStatus status) {
                        TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, invocation, status);
                        try {
                            return invocation.proceedWithInvocation();
                        }
                        catch (Throwable ex) {
                            completeTransactionAfterThrowing(txInfo, ex);
                            throw ex;
                        }
                        finally {
                            cleanupTransactionInfo(txInfo);
                        }
                    }
                });
    }
}

3. TransactionAttributeSource 接口

TransactionAttributeSource 接口用于获取方法上的事务属性。Spring 通常使用 AnnotationTransactionAttributeSource 来解析 @Transactional 注解。

4. PlatformTransactionManager 接口

PlatformTransactionManager 是 Spring 中用于管理事务的核心接口。不同的数据访问技术有不同的实现,例如 DataSourceTransactionManagerJpaTransactionManager 等。

5. 事务管理流程

  1. 创建代理对象

    • Spring 使用 JDK 动态代理或 CGLIB 代理来创建目标对象的代理。
    • 代理对象在方法调用前后插入事务管理逻辑。
  2. 拦截方法调用

    • TransactionInterceptor 在方法调用前检查是否有 @Transactional 注解,并根据注解中的配置决定是否需要开启新的事务。
    • 如果需要开启新事务,则调用 PlatformTransactionManager 的 getTransaction 方法开始一个新的事务。
    • 执行目标方法。
  3. 处理结果和异常

    • 如果目标方法执行成功且没有抛出异常,则调用 PlatformTransactionManager 的 commit 方法提交事务。
    • 如果目标方法抛出异常,则调用 PlatformTransactionManager 的 rollback 方法回滚事务。
显示全文