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)。当子事务出现异常时,它会回滚到自己的保存点,而不会影响到父事务的状态。当子事务提交时,它会增加自己的提交计数器,而不会立刻提交事务,只有当所有子事务都提交后,父事务才会提交。