c语言编程笔录

首页 >   > 笔记大全

笔记大全

spring的事务传播属性REQUIRED_NESTED的原理介绍

更新时间:2023-11-21

概述

REQUIRED_NESTED是Spring框架中的事务传播属性之一,它表示开启一个新的嵌套事务并参与到当前事务中,如果不存在当前事务,则开启一个新的事务。它是通过对当前事务的嵌套来实现的。如果当前环境中不存在事务,则该传播行为相当于REQUIRED。

使用方式

在Spring中,我们可以通过@Transactional注解来设置当前方法的事务属性,其中propagation属性就是用来设置事务的传播属性的。REQUIRED_NESTED是其中的一种,例如下面的例子:

@Transactional(propagation = Propagation.REQUIRED_NESTED)
public void insertRows(){
    // do something
}

代码实现

下面我们来看一下Spring是如何实现REQUIRED_NESTED的。在Spring中,事务的开启是通过TransactionInterceptor来实现的,具体来说,它是通过获取当前的事务管理器(PlatformTransactionManager)来开启事务的。在REQUIRED_NESTED中,当当前环境中已经存在事务时,会通过获取当前事务中嵌套的事务来开启一个新的嵌套事务。具体的实现可以参考下面的代码:

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
    //1. 判断该方法是否带有@Transactional注解
    TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
    //2. 获取当前事务状态
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
    return execute(new TransactionCallback<Object>() {
        public Object doInTransaction(TransactionStatus status) {
            //3. 判断是否存在当前事务,如果不存在,那么创建一个新的事务
            DefaultTransactionDefinition txDef = new DefaultTransactionDefinition(txAttr);
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txDef, joinpointIdentification);
            Object retVal;
            try {
                //4. 在当前事务中执行业务逻辑
                retVal = invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
                //5. 事务回滚
                rollbackOnException(txInfo, ex);
                throw ex;
            }
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }
    }, txAttr, joinpointIdentification);
}

嵌套事务的实现

在REQUIRED_NESTED中,所有的子事务都会从父事务中继承事务的特性。子事务和父事务之间是相互独立的,它们也拥有自己的保存点(SavePoint)。当子事务出现异常时,它会回滚到自己的保存点,而不会影响到父事务的状态。当子事务提交时,它会增加自己的提交计数器,而不会立刻提交事务,只有当所有子事务都提交后,父事务才会提交,具体的实现可以参考下面的代码:

public void startNestedTransaction() {
    if (this.savepoint == null) {
        throw new TransactionUsageException("Cannot create nested transaction without a savepoint");
    }
    this.savepointManager.createSavepoint();
    this.nestedTransactionStarted = true;
}

public void commitNestedTransaction() {
    if (!this.nestedTransactionStarted) {
        throw new TransactionUsageException("No nested transaction started; cannot commit");
    }
    this.savepointManager.releaseSavepoint();
    this.nestedTransactionStarted = false;
}

public void rollbackNestedTransaction() throws TransactionException {
    if (!this.nestedTransactionStarted) {
        throw new TransactionUsageException("No nested transaction started; cannot roll back");
    }
    this.savepointManager.rollbackToSavepoint();
    this.nestedTransactionStarted = false;
}

总结

在Spring中,REQUIRED_NESTED通过对当前事务的嵌套来实现,当当前环境中已经存在事务时,会通过获取当前事务中嵌套的事务来开启一个新的嵌套事务。所有的子事务都会从父事务中继承事务的特性。它们也拥有自己的保存点(SavePoint)。当子事务出现异常时,它会回滚到自己的保存点,而不会影响到父事务的状态。当子事务提交时,它会增加自己的提交计数器,而不会立刻提交事务,只有当所有子事务都提交后,父事务才会提交。