【从源码的视角 全貌了解Spring 事务的传播特性】

本文从源码角度深入探讨Spring事务的传播特性,包括PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY等不同模式的实战结论和原因分析,详细解释了在各种组合情况下事务如何回滚或不回滚。
摘要由CSDN通过智能技术生成

1、Spirng事务配置文件解析入口:

AbstractBeanDefinitionParser入口方法是parse 方法

2、Spring事务调用入口:

TransactionInterceptor类实现了MethodInterceptor接口,入口方法是 invoke 方法

事务传播性

@Transaction中的propagation的可以配置事务的传播性,网上介绍的很多,就直接复制一段

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 (也是默认策略)

PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常

Spring事务的传播特性是为了解决服务之间相互调用产生的一套规则,如Aservice和Bservice A为外层service B为内层service

A中调用B ,传播特性主要是针对内层事务的修饰限定词,以下为实验结论及原因

support

    1、结论:A有事务,事务传播属性为support,B无事务 A无异常 B有异常 则 AB 不回滚

         原因:spring在当前A的外层无事务的情况下,spring会创建一个空的transcation对象,当发生异常时,需要回滚,但transcation是空对象,所以无法回滚

         源码片段:AbstractPlatformTransactionManager类的getTransaction方法;

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)

                       throws TransactionException {



               // Use defaults if no transaction definition given.

               TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());



               Object transaction = doGetTransaction();

               boolean debugEnabled = logger.isDebugEnabled();



               if (isExistingTransaction(transaction)) {

                       // Existing transaction found -> check propagation behavior to find out how to behave.

                       return handleExistingTransaction(def, transaction, debugEnabled);

               }



               // Check definition settings for new transaction.

               if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {

                       throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());

               }



               // No existing transaction found -> check propagation behavior to find out how to proceed.

              if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {

                       throw new IllegalTransactionStateException(

                                      "No existing transaction found for transaction marked with propagation 'mandatory'");

               }

               else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||

                               def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||

                               def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

                       SuspendedResourcesHolder suspendedResources = suspend(null);

                       if (debugEnabled) {

                              logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);

                       }

                       try {

                               return startTransaction(def, transaction, debugEnabled, suspendedResources);

                       }

                       catch (RuntimeException | Error ex) {

                               resume(null, suspendedResources);

                               throw ex;

                       }

               }

               else {

                       // Create "empty" transaction: no actual transaction, but potentially synchronization.

                       if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {

                               logger.warn("Custom isolation level specified but no actual transaction initiated; " +

                                              "isolation level will effectively be ignored: " + def);

                       }

                       boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);

                       return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);

               }

        }

 

此片段会生产一个空对象

else {

            // Create "empty" transaction: no actual transaction, but potentially synchronization.

            if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {

                logger.warn("Custom isolation level specified but no actual transaction initiated; " +

                        "isolation level will effectively be ignored: " + def);

            }

            boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);



            //返回一个status中transaction为null的对象



            return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);

        }

源码片段:AbstractPlatformTransactionManager类的processRollback方法

private void processRollback(DefaultTransactionStatus status, boolean unexpected) {

               try {

                       boolean unexpectedRollback = unexpected;



                       try {

                               triggerBeforeCompletion(status);



                               if (status.hasSavepoint()) {

                                      if (status.isDebug()) {

                                              logger.debug("Rolling back transaction to savepoint");

                                      }

                                      status.rollbackToHeldSavepoint();

                               }

                               else if (status.isNewTransaction()) {

                                      if (status.isDebug()) {

                                              logger.debug("Initiating transaction rollback");

                                      }

                                      doRollback(status);

                               }

                               else {

                                      // Participating in larger transaction

                                      if (status.hasTransaction()) {

                                              if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {

                                                     if (status.isDebug()) {

                                                             logger.debug("Participating transaction failed - marking existing transaction as rollback-only");

                                                     }

                                                     doSetRollbackOnly(status);

                                              }

                                              else {

                                                     if (status.isDebug()) {

                                                             logger.debug("Participating transaction failed - letting transaction originator decide on rollback");

                                                     }

                                              }

                                      }

                                      else {

                                              logger.debug("Should roll back transaction but cannot - no transaction available");

                                      }

                                      // Unexpected rollback only matters here if we're asked to fail early

                                      if (!isFailEarlyOnGlobalRollbackOnly()) {

                                              unexpectedRollback = false;

                                      }

                               }

                       }

                       catch (RuntimeException | Error ex) {

                               triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);

                               throw ex;

                       }



                       triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);



                       // Raise UnexpectedRollbackException if we had a global rollback-only marker

                       if (unexpectedRollback) {

                               throw new UnexpectedRollbackException(

                                              "Transaction rolled back because it has been marked as rollback-only");

                       }

               }

               finally {

                       cleanupAfterCompletion(status);

               }

        }

此处判断没有transaction

if (status.hasTransaction()) {

                        if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {

                            if (status.isDebug()) {

                                logger.debug("Participating transaction failed - marking existing transaction as rollback-only");

                            }

                            doSetRollbackOnly(status);

                        }

                        else {

                            if (status.isDebug()) {

                                logger.debug("Participating transaction failed - letting transaction originator decide on rollback");

                            }

                        }

                    }

                    else {

                        logger.debug("Should roll back transaction but cannot - no transaction available");

                    }

 

2、结论:A无事务,B有事务传播属性为support, A无异常 B有异常 则 AB 不回滚 (同第一种情况)

3、结论:A有事务,B有事务传播属性为support, A无异常 B有异常 则 AB 回滚 (AB在同一个事务中,使用A的事务)


Not support

1、A中有事务,B有事务传播属性为not support, A无异常 B有异常 则 A回滚 B 不回滚 (AB不在同一事务中)

 

原因:A中的事务按照原样执行,B中的事务则是挂起当前事务

源码片段:

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {

   if (debugEnabled) {

      logger.debug("Suspending current transaction");

   }

   Object suspendedResources = suspend(transaction);

   boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);

   return prepareTransactionStatus(

         definition, null, false, newSynchronization, debugEnabled, suspendedResources);

}

 


 

required

1、结论:A有事务B有事务 A无异常 B有异常 则 AB 同时回滚  (AB使用同一个事务)

     原因:spring会产生一个transaction对象,当发生异常时,可以调用rollback方法

      1)源码片段:AbstractPlatformTransactionManager类的getTransaction方法;

else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||

      def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||

      def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

   SuspendedResourcesHolder suspendedResources = suspend(null);

   if (debugEnabled) {

      logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);

   }

   try {

      return startTransaction(def, transaction, debugEnabled, suspendedResources);

   }

   catch (RuntimeException | Error ex) {

      resume(null, suspendedResources);

      throw ex;

   }

}

    2)源码片段:AbstractPlatformTransactionManager类的processRollback方法

else if (status.isNewTransaction()) {

                    if (status.isDebug()) {

                        logger.debug("Initiating transaction rollback");

                    }

                    doRollback(status);

                }

2、 A有事务B无事务 A无异常 B有异常 则 AB 同时回滚  (AB处于同一个事务当中) 

3、 A无事务B有事务 A无异常 B有异常 则 A不回滚 (A与B不处于同一个事务中,A无事务处理)


required new

1、 A有事务B无事务 A无异常 B有异常 则 AB 同时回滚(AB处于同一个事务当中,B包裹在A事务当中)

 2、A无事务B有事务 A无异常 B有异常 则 A不回滚B回滚(A无事务B有事务)

 3、A有事务B有事务,事务传播属性为required new, A无异常 B有异常 则 AB 同时回滚(AB处于不同的事务当中)

 原因:A有事务,B会开一个新的事务,B出错,B会回滚,A也回回滚,因为开启的事务当中B服务抛出异常,导致A事务回滚

 源码片段:

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {

                       if (debugEnabled) {

                               logger.debug("Suspending current transaction, creating new transaction with name [" +

                                              definition.getName() + "]");

                       }

                       SuspendedResourcesHolder suspendedResources = suspend(transaction);

                       try {

                               return startTransaction(definition, transaction, debugEnabled, suspendedResources);

                       }

                       catch (RuntimeException | Error beginEx) {

                               resumeAfterBeginException(transaction, suspendedResources, beginEx);

                               throw beginEx;

                       }

               }

nerver

 1、A有事务,事务属性为nerver ,B无事务 A无异常 B有异常 则 AB 不回滚(会创建空事务对象,无法回滚)

 2、A有事务,B有事务传播属性为nerver, A无异常 B有异常 则 抛出异常 AB回滚

  原因:外层有事务,内层事务传播属性为never 则表示外层不能有事务,抛出异常,回滚数据

  AbstractPlatformTransactionManager类handleExistingTransaction方法

private TransactionStatus handleExistingTransaction(

                       TransactionDefinition definition, Object transaction, boolean debugEnabled)

                       throws TransactionException {



               if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {

                       throw new IllegalTransactionStateException(

                                      "Existing transaction found for transaction marked with propagation 'never'");

               }



               if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {

                       if (debugEnabled) {

                               logger.debug("Suspending current transaction");

                       }

                       Object suspendedResources = suspend(transaction);

                       boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);

                       return prepareTransactionStatus(

                                     definition, null, false, newSynchronization, debugEnabled, suspendedResources);

               }



               if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {

                       if (debugEnabled) {

                               logger.debug("Suspending current transaction, creating new transaction with name [" +

                                              definition.getName() + "]");

                       }

                       SuspendedResourcesHolder suspendedResources = suspend(transaction);

                       try {

                               return startTransaction(definition, transaction, debugEnabled, suspendedResources);

                       }

                       catch (RuntimeException | Error beginEx) {

                               resumeAfterBeginException(transaction, suspendedResources, beginEx);

                               throw beginEx;

                       }

               }



               if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

                       if (!isNestedTransactionAllowed()) {

                               throw new NestedTransactionNotSupportedException(

                                              "Transaction manager does not allow nested transactions by default - " +

                                              "specify 'nestedTransactionAllowed' property with value 'true'");

                       }

                       if (debugEnabled) {

                               logger.debug("Creating nested transaction with name [" + definition.getName() + "]");

                       }

                       if (useSavepointForNestedTransaction()) {

                               // Create savepoint within existing Spring-managed transaction,

                               // through the SavepointManager API implemented by TransactionStatus.

                               // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.

                               DefaultTransactionStatus status =

                                             prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);

                               status.createAndHoldSavepoint();

                               return status;

                       }

                       else {

                               // Nested transaction through nested begin and commit/rollback calls.

                               // Usually only for JTA: Spring synchronization might get activated here

                               // in case of a pre-existing JTA transaction.

                               return startTransaction(definition, transaction, debugEnabled, null);

                       }

               }



               // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.

               if (debugEnabled) {

                       logger.debug("Participating in existing transaction");

               }

               if (isValidateExistingTransaction()) {

                       if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {

                               Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();

                               if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {

                                      Constants isoConstants = DefaultTransactionDefinition.constants;

                                      throw new IllegalTransactionStateException("Participating transaction with definition [" +

                                                     definition + "] specifies isolation level which is incompatible with existing transaction: " +

                                                     (currentIsolationLevel != null ?

                                                                     isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :

                                                                     "(unknown)"));

                               }

                       }

                       if (!definition.isReadOnly()) {

                               if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {

                                      throw new IllegalTransactionStateException("Participating transaction with definition [" +

                                                     definition + "] is not marked as read-only but existing transaction is");

                               }

                       }

               }

               boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

               return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);

        }

 

源码片段:此处会直接抛出异常,然后回滚

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {

                       throw new IllegalTransactionStateException(

                                      "Existing transaction found for transaction marked with propagation 'never'");

               }

3、A无事务B有事务 ,传播属性为nerver、A无异常 B有异常 则 A 不回滚(无事务对象)B不回滚(事务空对象

else {

                       // Create "empty" transaction: no actual transaction, but potentially synchronization.

                       if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {

                               logger.warn("Custom isolation level specified but no actual transaction initiated; " +

                                              "isolation level will effectively be ignored: " + def);

                       }

                       boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);

                       return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);

               }

 mandatory

1、A无事务B有事务,传播熟悉为mandatory, A无异常 B有异常 则 抛出异常No existing transaction found for transaction marked with propagation 'mandatory

 原因:mandatory表示外层事务必须存在

 源码片段

if (isExistingTransaction(transaction)) {

                       // Existing transaction found -> check propagation behavior to find out how to behave.

                       return handleExistingTransaction(def, transaction, debugEnabled);

               }

// Check definition settings for new transaction.

if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {

                       throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());

               }



// No existing transaction found -> check propagation behavior to find out how to proceed.

if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {

                       throw new IllegalTransactionStateException(

                                      "No existing transaction found for transaction marked with propagation 'mandatory'");

               }

    先判断是否存在外层事务,如果存在则使用外层事务,如果不存在则报错

  2、A有事务B有事务 A无异常 B有异常 则 AB回滚(AB使用同一个事务)

   原因:如果A有事务,B有事务,且B使用mandatory,则AB回滚(AB使用同一个事务)

   源码片段:

if (isExistingTransaction(transaction)) {

                       // Existing transaction found -> check propagation behavior to find out how to behave.

                       return handleExistingTransaction(def, transaction, debugEnabled);

               }

nested

    1、A有事务B有事务 A无异常 B有异常 则 AB回滚(AB在同一个事务中)

     原因:A使用事务,B使用nested,AB存在同一个事务中

     源码片段

if (isExistingTransaction(transaction)) {

                       // Existing transaction found -> check propagation behavior to find out how to behave.

                       return handleExistingTransaction(def, transaction, debugEnabled);

               }

 


    2、A有事务B无事务 A无异常 B有异常 则 AB回滚

    原因:A使用事务,B使用nested,AB存在同一个事务中


    3、A无事务B有事务 A无异常 B有异常 则 A不回滚 B回滚

    原因:A无事务,B有事务,A为外层事务,B为内层事务,A无异常,直接提交数据,B有异常,回滚

彩蛋

package cn.com.demo.service.impl;

import cn.com.demo.entity.Student;
import cn.com.demo.entity.Teacher;
import cn.com.demo.mapper.StuMapper;
import cn.com.demo.service.StuService;
import cn.com.demo.service.TeaService;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;
    @Autowired
    private TeaService teaService;

    /**
     * 期望:在addStu2发生异常的情况下,addStu2回滚 原因:addStu2新建一个事务,在事务周期内发生回滚操作
     * 结果:addStu2不发生回滚 原因:因为spring事务采用的是代理模式,在将事务组织到调用addStu这个切入点时
     * 调用addStu是代理对象,但是调用addStu2却不是代理对象,是真实对象,所以事务失效,导致addStu2无法回滚
     * 解决此问题,需要获取代理对象,使用代理对象来执行addStu2方法在配置文件中开启获取代理对象的配置<aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
     * StuService o = (StuService)AopContext.currentProxy();
     * o.addStu2(student);
     * @param student
     * @return
     */
    @Override
    @Transactional
    public boolean addStu(Student student) {
        try{
            addStu2(student);
        }catch (Exception e){
            e.printStackTrace();
        }
        stuMapper.addStu(student);
        return false;
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public boolean addStu2(Student student){
        stuMapper.addStu(student);
        int i = 1/0;
        return false;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值