Spring (22)事务传播

49 阅读3分钟

事务传播行为是指当一个事务方法被另一个事务方法调用时,事务应该如何进行。这是Spring事务管理的核心概念之一,它解决了业务流程中不同事务之间的交互问题。

Spring提供了多种类型的事务传播行为,以下是其中一些最常用的:

  1. REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是默认设置。
  2. REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
  3. SUPPORTS:如果当前存在事务,就加入到这个事务中,否则可以以非事务方式执行。
  4. NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  5. MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
  6. NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  7. NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则表现与REQUIRED一样。

源码解析

在Spring的源码中,TransactionAspectSupport类是负责处理事务逻辑的地方。事务的传播行为是在AbstractPlatformTransactionManager实现里面处理的,具体的传播行为实现依赖于TransactionDefinition接口的实现类。

下面是一个简化的方法,演示了Spring如何处理事务传播行为:

public class TransactionAspectSupport {

    protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable {

        // 如果有事务,这里会获取到
        TransactionInfo txInfo = createTransactionIfNecessary(method, targetClass);

        Object retVal;
        try {
            // 执行业务方法
            retVal = invocation.proceedWithInvocation();
        }
        catch (Throwable ex) {
            // 如果出现异常,执行回滚
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        }
        finally {
            // 清理事务信息
            cleanupTransactionInfo(txInfo);
        }

        // 提交事务
        commitTransactionAfterReturning(txInfo);
        return retVal;
    }
}

在这个方法中,首先检查是否需要根据当前传播行为创建或加入事务(createTransactionIfNecessary)。然后执行业务方法(proceedWithInvocation)。如果业务方法执行过程中出现异常,则进行回滚(completeTransactionAfterThrowing)。最后,在业务方法正常执行完成后,提交事务(commitTransactionAfterReturning)。

代码演示

现在让我们看一些实际的代码来演示不同的事务传播行为。为了简化示例,我们假设使用声明式事务管理,通过注解来定义事务的传播行为。

REQUIRED

@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
    innerMethod();
}

@Transactional(propagation = Propagation.REQUIRED)
public void innerMethod() {
    // 业务逻辑
}

在这个例子中,如果outerMethod在事务中被调用,innerMethod会加入到这个事务中。如果outerMethod没有在事务中被调用,会开始一个新的事务。

REQUIRES_NEW

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void outerMethod() {
    innerMethod();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod() {
    // 业务逻辑
}

无论outerMethod是否在事务中,innerMethod总是会在一个新的事务中执行,并且挂起任何现有的事务。

NESTED

@Transactional(propagation = Propagation.NESTED)
public void outerMethod() {
    innerMethod();
}

@Transactional(propagation = Propagation.NESTED)
public void innerMethod() {
    // 业务逻辑
}

outerMethod中调用innerMethod时,如果outerMethod已经在一个事务中,innerMethod会在一个嵌套事务中执行。如果outerMethod不在事务中,它的行为就像REQUIRED

事务的传播行为是Spring事务管理中的高级特性之一,它允许开发者精确控制事务的边界和事务之间的交互。理解和正确使用事务传播行为对于编写可靠的数据访问代码和维护复杂业务逻辑至关重要。在实际应用中,应该根据具体业务需求和事务的边界来选择适当的事务传播行为。