Spring 事务实现分析

1. Spring 事务简介

Spring 本身并不实现事务,Spring事务 的本质 还是 底层数据库 对事务的支持,没有 数据库 事务的支持,Spring事务就不会生效。

Spring 事务 提供一套抽象的事务管理,并且结合 Spring IOC 和 Spring AOP,简化了应用程序使用数据库事务,通过声明式事务,可以做到对应用程序无侵入的实现事务功能。例如 使用JDBC 操作数据库,想要使用事务的步骤为:

1、获取连接 Connection con = DriverManager.getConnection()

2、开启事务con.setAutoCommit(true/false);

3、执行CRUD

4、提交事务/回滚事务 con.commit() / con.rollback();

5、关闭连接 conn.close();

采用Spring 事务后,只需要 关注第3步的实现,其他的步骤 都是Spring 完成。

Spring事务的本质 其实就是 AOP 和 数据库事务,Spring 将数据库的事务操作提取为 切面,通过AOP的方式 增强 事务方法。

2. 事务传播行为

事务传播行为类型 说明
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

3. 使用Spring事务

3.1. 通过 PlatformTransactionManager使用(不推荐)

@Test
    public void test12(){
    // 默认的事务定义
        DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
        //开启事务。
        TransactionStatus transaction = transactionManager.getTransaction(defaultTransactionDefinition);
        try {
            Account account = new Account();
            account.setUserName("wokalakala");
            List accountList = accountMapper.queryAccountList(account);
        }catch (Exception e){
        //事务回滚 
            transactionManager.rollback(transaction);
        }
        //事务提交
        transactionManager.commit(transaction);
    }

3.2. 通过TransactionTemplate 使用事务

@Test
    public void testTransactionTemplate(){
        TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
        List accountList = transactionTemplate.execute(status -> {
            Account account = new Account();
            account.setUserName("wokalakala");
            return accountMapper.queryAccountList(account);
        });
    }

3.3. 声明式事务

我们经常使用的 方式,通过AOP 实现,对应用程序 侵入较少,采用注解的方式比较简单方便,省去XML 繁琐的配置。

4. 组件介绍

4.1事务管理 PlatformTransactionManager

PlatformTransactionManager 是 Spring 事务结构中的核心接口,Spring并不直接管理事务,而是提供了多种事务管器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现.Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。此接口的内容如下:

Public interface PlatformTransactionManager(){  
// 由TransactionDefinition得到TransactionStatus对象
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; 
// 提交
Void commit(TransactionStatus status) throws TransactionException;  
// 回滚
Void rollback(TransactionStatus status) throws TransactionException;  
} 

通过PlatformTransactionManager的接口 可以看出,Spring 事务的 的三个核心方法,事务开启 ,提交事务,回滚事务,Spring 事务功能的实现 都是围绕这三个方法来实现。

Spring 事务实现分析_第1张图片
20160324011156424 (1).jpg

4.2 TransactionInfo

事务信息对象,包括一个事务所有的信息,持有 事务管理器,事务定义对象,目标方法唯一标识,事务状态对象,外层的TransactionInfo,外层的TransactionInfo 用于在应用程序中获取 当前的TransactionInfo 对象。

Spring 事务实现分析_第2张图片
未命名文件 (2).png

4.3 TransactionStatus

表示一个事务状态,在应用程序中可以通过 TransactionInterceptor.currentTransactionStatus() 的静态函数获取到。

  1. 持有事务对象 ,使用JDBC 事务时 ,事务对象为 DataSourceTransactionObject,
  2. 对保存点的支持,可以在应用程序中 通过 设置保存点 ,在事务回滚时,回滚到 保存点,而不是回滚部分。

4.4 TransactionDefinition

事务定义对象,封装了@Transactional 注解中设置的各种信息,通过收集@Transactional属性信息,获取到 一个 TransationalDefinition ,有了事务定义信息 就可以通过PlatformTransactionManager开启事务 或者 复用一个事务了。

4.5 TransationSynchronization 事务同步回调接口

事务同步回调接口,在事务 周期的各个点 执行回调 方法。比如 挂起 ,继续,提交前后 ,完成前后 。用于 管理 应用程序在事务周期中绑定的资源。在Spring - Mybatis 整合时,正式Mybatis 正式利用了TransationSynchronization同步器,才让Mybatis 的事务管理交给了 Spring 事务来管理。

4.6 TransactionSynchronizationManager 事务同步回调的管理器

在事务运行过程中,需要保存一些状态,比如 数据库连接,

ThreadLocal> resources - 应用代码随事务的声明周期绑定的对象  
ThreadLocal> synchronizations-使用的同步器,用于应用扩展  
ThreadLocal currentTransactionName-事务的名称  
ThreadLocal currentTransactionReadOnly-事务是否是只读  
ThreadLocal currentTransactionIsolationLevel-事务的隔离级别  
ThreadLocal actualTransactionActive-是否实际的开启了事务,如果加入 到 别的事务,就不是实际开启事务。

4.7 SuspendedResourceHolder 挂起的资源持有对象

在挂起一个事务时,用于记录被挂起事务的运行时信息,这些信息就是TransactionSynchronizationManager中记录的事务信息。然后将这些信息 保存在 新的DefaultTransactionStatus对象中,便于内部事务运行结束后,恢复外层事务。

5. Spring 事务实现

Spring事务 把 整个事务流程 模板化,采用AOP的形式 增强到 需要事务 的方法,所以 按照 AOP 的 实现 一定存在 一个事务的增强器,这个增强器就是 BeanFactoryTransactionAttributeSourceAdvisor,该增强器中有个环绕通知TransactionInterceptor,所有的事务逻辑 都在这个类的Invoke 方法中,分析Spring 事务实现就从这个函数开始。

  • invoke
//invocation 维护了 AOP 拦截器链 ,执行 invocation.prcess 方法 会沿着拦截器链执行下去直到目标方法。
public Object invoke(final MethodInvocation invocation) throws Throwable {
//获取目标对象
        Class targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
        // 执行 父类 TransactionAspectSupport's invokeWithinTransaction...
        return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
            @Override
            public Object proceedWithInvocation() throws Throwable {
            //继续一下执行下拦截器 也可能式目标方法
                return invocation.proceed();
            }
        });
    }
  • TransactionAspectSupport's invokeWithinTransaction
protected Object invokeWithinTransaction(Method method, Class targetClass, final InvocationCallback invocation)
            throws Throwable {

1. 准备事务的基本信息
        // If the transaction attribute is null, the method is non-transactional.
        //事务定义 TransactionAttribute 是 TransationDefinition 的子类
        final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
        //获取 事务管理器 ,这里是一个策略模式,根据 事务定义 指定的 事务管理器 获取到 指定的 事务管理器。
        final PlatformTransactionManager tm = determineTransactionManager(txAttr);
        //连接点  标识
        final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
            // Standard transaction demarcation with getTransaction and commit/rollback calls.
        2. 开启事务 
        //如果必要 才会开启事务,这里会根据 事务的传播行为 信息 来决定是否开启事务 还是 加入一个已经存在的事务。这里会涉及到事务的挂起 
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
            Object retVal = null;
            try {
            执行目标方法或者 执行AOP 拦截器链中的下一个拦截器。
                // This is an around advice: Invoke the next interceptor in the chain.
                // This will normally result in a target object being invoked.
                retVal = invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
                // target invocation exception
                3. 事务的回滚 
                //是否回滚 会根据 rollback 属性 判断
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
            清理事务信息
                cleanupTransactionInfo(txInfo);
            }
            4. 提交事务
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }
        }
        //省略部代码

5.1 准备事务

准备事务 主要是做了两件事情

  1. 收集@Transactional注解属性信息,生成 事务定义对象。
    由于@Transactional可以作用在类上 又可以作用在方法上,所以在收集属性信息的时候,就考虑到这种情况。
    AnnotationTransactionAttributeSource 类就是用来解析类和方法上面的@Transactional 注解属性。
    那么到底 先解析类上面的 还是 先解析 方法上面的注解呢?如果方法上面 和 类上面 同时存在呢,是完整替换? 还是取并集?
    定义解析@Transactional 注解的 逻辑定义在 其父类AbstractFallbackTransactionAttributeSource的computeTransactionAttribute,通过查看代码 便可以一目了然:
protected TransactionAttribute computeTransactionAttribute(Method method, Class targetClass) {
        // Don't allow no-public methods as required.
        if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
            return null;
        }

        // Ignore CGLIB subclasses - introspect the actual user class.
        Class userClass = ClassUtils.getUserClass(targetClass);
        // The method may be on an interface, but we need attributes from the target class.
        // If the target class is null, the method will be unchanged.
        Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
        // If we are dealing with method with generic parameters, find the original method.
        specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

//首先 解析方法上面 的 属性信息
        // First try is the method in the target class.
        TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
    //如果方法上面存在 就返回。
        if (txAttr != null) {
            return txAttr;
        }

//其次 解析作用在类上面的注解属性信息,如果找到 就返回。
        // Second try is the transaction attribute on the target class.
        txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
        if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
            return txAttr;
        }

//解析接口方法上面的注解属性信息 ,如果找到返回。
        if (specificMethod != method) {
            // Fallback is to look at the original method.
            txAttr = findTransactionAttribute(method);
            if (txAttr != null) {
                return txAttr;
            }
            //最后 解析接口上面的注解信息。
            // Last fallback is the class of the original method.
            txAttr = findTransactionAttribute(method.getDeclaringClass());
            if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
                return txAttr;
            }
        }

        return null;
    }

通过上面的代码可以看出来,@Transactional 注解定义在不同位置的 优先级
为 ,实列方法,实列类,接口方法,接口类。不会取并集 ,也不会覆盖,按照优先级查找,直到找到为止。

  • 用到了缓存
    虽然解析注解属性不是那么的耗时,但是也不能每次执行事务方法都要解析一次注解属性,所以在解析注解的时候Spring采用了缓存,这样就只需要一次解析注解,而后的每次执行都会存缓存中获取。这是一个典型的拿空间换时间的列子。采用缓存的代码在其父类 AbstractFallbackTransactionAttributeSource 的getTransactionAttribute函数。

在使用缓存的时候 难免遇到缓存穿透的现象,就是用key 获取缓存的时候 没有 获取到对象,然后就要去解析@Transactional ,结果发现 还是没有,此后的每次调用都会持续这个现象,所以Spring 在发现 不存在的时候 就会定义一个特殊的 value 放到缓存中,以标识 这个已经解析过了,确实不存在。

  • 解析注解的时机
    解析的时机 是在IOC 第一次初始化 Bean的时候,具体点就是 在为目标对象匹配增强器的时候,会触发解析注解。
  1. 获取事务管理器

如果使用@Transactional 指定了使用哪个事务管理器 ,就会获取响应的事务管理器。如果没有 就从IOC 容器中获取。

5.2 开启事务

收集到了事务定义信息,和 事务管理器之后,就可以 利用PlatformTransactionManager.getTransactional 开启事务了,但是开启事务,有很多情况需要考虑,比如繁多的事务传播行为,比如是否已经存在事务,不同的条件都会影响是否要开启一个新事务。有的传播行为 还会设计到 挂起 已经存在的事务。也是相当复杂的。

protected TransactionInfo createTransactionIfNecessary(
            PlatformTransactionManager tm, TransactionAttribute txAttr, final String joinpointIdentification) {

        // 采用 委托的方式 包装 事务定义 对象.
        if (txAttr != null && txAttr.getName() == null) {
            txAttr = new DelegatingTransactionAttribute(txAttr) {
                @Override
                public String getName() {
                    return joinpointIdentification;
                }
            };
        }

        TransactionStatus status = null;
        if (txAttr != null) {
            if (tm != null) {
                //调用 事务管理器开启事务。
                status = tm.getTransaction(txAttr);
            }
            else {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
                            "] because no transaction manager has been configured");
                }
            }
        }
    //封装成事务信息对象。
        return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
    }
AbstractPlatformTransactionManager. getTransaction

这是一个模版方法 ,提供了两个抽象方法 供 子类实现。

该方法主要逻辑

  1. 判断当前线程是否存在事务
  2. 存在事务 根据 事务传播行为 创建事务 或 加入当前事务 或 抛出不支持异常
  3. 不存在事务 判断 传播行为是否 为 TransactionDefinition.PROPAGATION_MANDATORY ,如果是抛出异常
  4. PROPAGATION_REQUIRED,PROPAGATION_REQUIRED_NEW ,TransactionDefinition.PROPAGATION_NESTED创建事务
  5. 不运行在事务中,创建空事务。
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
    //获取事务,从线程绑定的信息中获取 事务,抽象方法 留给子类实现。
   Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
   boolean debugEnabled = logger.isDebugEnabled();
        if (definition == null) {
            // Use defaults if no transaction definition given.
            definition = new DefaultTransactionDefinition();
        }
//  判断是否 已经存在事务
        if (isExistingTransaction(transaction)) {
            //已经存在事务 根据传播行为 创建事务 或者 加入事务
            return handleExistingTransaction(definition, transaction, debugEnabled);
        }

        // 检查超时时间 的设置 是否合法
  
        if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
            throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
        }

        //如果传播行为 强制 PROPAGATION_MANDATORY 
        if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
            throw new IllegalTransactionStateException(
                    "No existing transaction found for transaction marked with propagation 'mandatory'");
        }
    //开启新事务
        else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
                definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
                definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
            SuspendedResourcesHolder suspendedResources = suspend(null);
            if (debugEnabled) {
                logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
            }
            try {
                boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
                DefaultTransactionStatus status = newTransactionStatus(
                        definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
                //抽象方法 开启事务。留给子类实现。
                doBegin(transaction, definition);
                prepareSynchronization(status, definition);
                return status;
            }
            catch (RuntimeException ex) {
                resume(null, suspendedResources);
                throw ex;
            }
            catch (Error err) {
                resume(null, suspendedResources);
                throw err;
            }
        }
        else {
            // Create "empty" transaction: no actual transaction, but potentially synchronization.
            if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
                logger.warn("Custom isolation level specified but no actual transaction initiated; " +
                        "isolation level will effectively be ignored: " + definition);
            }
            boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
            return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
        }
    }
DataSourceTransactionManager.doBegin

这里实际获取数据库 连接 开启事务的地方,从DataSource 中获取连接,并且设置 自动提交为false ,

  1. 获取 数据库连接
  2. 设置 数据库连接自动提交 为 false,开启事务
  3. 绑定数据库连接到 线程
/**
     * This implementation sets the isolation level but ignores the timeout.
     */
    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        Connection con = null;

        try {
        //如果当前不存在数据库 
            if (!txObject.hasConnectionHolder() ||
                    txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                    //获取数据库连接,如果采用数据库连接池 这里就是连接池对象。
                Connection newCon = this.dataSource.getConnection();
                //设置连接到 事务对象中。
                txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
            }
            
            txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
            
            con = txObject.getConnectionHolder().getConnection();
//记录上一个 事务的隔离级别 ,如果没有外层事务 ,隔离级别就是null
            Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
            txObject.setPreviousIsolationLevel(previousIsolationLevel);

            //设置自动提交 为false,如果使用 连接池,连接池 或许已经设置自动提交为false了,所以这里先判断一下。
            if (con.getAutoCommit()) {
                txObject.setMustRestoreAutoCommit(true);
                if (logger.isDebugEnabled()) {
                    logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                }
                con.setAutoCommit(false);
            }
//如果事务是只读事务 ,那么就会执行 SQL "SET TRANSACTION READ ONLY".
            prepareTransactionalConnection(con, definition);
            txObject.getConnectionHolder().setTransactionActive(true);

            int timeout = determineTimeout(definition);
            if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
                txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
            }

            // 如果是一个新的连接 ,绑定数据库连接到当前线程
            if (txObject.isNewConnectionHolder()) {
            //调用 事务同步回调管理器 的 绑定资源方法,key= dataSource ,key = ConnectionHodler
                TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
            }
        }
        catch (Throwable ex) {
            if (txObject.isNewConnectionHolder()) {
            //异常之后 释放连接,
                DataSourceUtils.releaseConnection(con, this.dataSource);
                txObject.setConnectionHolder(null, false);
            }
            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
        }
    }
事务挂起

当线程中已经存在事务,在某些事务传播行为下就需要挂起外层事务,
比如PROPAGATION_NOT_SUPPORTED:不能运行在一个事务中,如果存在事务就挂起当前事务,执行。
PROPAGATION_REQUIRES_NEW: 必须运行在一个新事务中,如果当前存在事务,则挂起当前事务,开启新事务执行。
如何实现挂起一个事务呢?
挂起事务需要完成几项工作:
1.TransactionSynchronizationManager 中解除绑定的 TransactionSynchronization 集合
2.重置当前事务名称绑定
3.重置事务只读属性绑定
4.重置事务隔离级别绑定
5.重置实际事务激活标志绑定
6.记录以上几部的数据,封装到 SuspendedResourceHolder对象中。
7.将SuspendedResourceHolder对象,交给内部事务 ,以便内部事务执行结束后,恢复外层事务。

事务恢复

如果内部事务出现异常或者 内部事务提交 都会触发外层事务的恢复,事务的恢复就是将内存事务TransactionStauts 中记录的挂起事务的信息,重新绑定到 TransactionSynchronizationManager中去。

5.3 事务回滚

如果事务运行过程中出现某些异常 会导致事务回滚,在JDBC中 我们执行connection.rollback()回滚事务,Spring事务也不列外,只是Spring 事务 在JDBC 的基础之上提供了更多丰富的功能,比如 指定某些异常进行回滚。
关于事务回滚rollback 设置,还有一个容易被忽视 和 误解的地方。就是如果我们设置rollbackFor = IllegalArgumentException.class 那么事务运行期间出现了IndexOutOfBoundsException异常会不会导致事务回滚?出现了 Error 错误会不会回滚?

处理事务回滚的在TransactionAspectSupport . completeTransactionAfterThrowing 函数中

  1. 首先判断 异常是否需要回滚。判断逻辑 最终是委托给 RuleBasedTransactionAttribute.rollbackOn
    public boolean rollbackOn(Throwable ex) {

        RollbackRuleAttribute winner = null;
        int deepest = Integer.MAX_VALUE;
        if (this.rollbackRules != null) {
        //遍历 查找 指定的 rollbackException 进行匹配
            for (RollbackRuleAttribute rule : this.rollbackRules) {
                int depth = rule.getDepth(ex);
                if (depth >= 0 && depth < deepest) {
                    deepest = depth;
                    winner = rule;
                }
            }
        }

        // 如果没有匹配到 采用默认的回滚规则进行判断。
        //默认的规则就是 ex instanceof RuntimeException || ex instanceof Error,所以 如果我们指定了rollback = IllegalArgumentException,当遇到 IndexOutOfBoundsException时 或者 Error 时也会回滚事务。
        if (winner == null) {
            logger.trace("No relevant rollback rule found: applying default rules");
            return super.rollbackOn(ex);
        }

        return !(winner instanceof NoRollbackRuleAttribute);
    }
  1. 如果需要回滚则会执行 AbstranctPlatformTransactionManager.processRollback函数
    2.1 if (status.hasSavepoint())
    如果存在保存点 则回滚到 保存点
    2.2 else if (status.isNewTransaction())
    如果 是一个新事务 执行回滚。
    2.3 . else if (status.hasTransaction())
    如果 是嵌套事务 设置 当前数据库链接 rollbackOnly

  2. 如果不需要回滚 则提交事务

  3. 触发钩子函数
    在回滚前后 会分别触发 TransactionSynchronuzation 的beforeCompletion,afterCompletion 函数,进行资源释放,连接关闭等。

5.4 事务提交

只有当事务是一个 新事务的时候才会进行提交,就是如果 有一个 内嵌事务传播 行为 PROPAGATION_SUPPORTS ,PROPAGATION_REQUIRED ,PROPAGATION_MANDATORY 的事务 执行完之后 不会 提交,会随着外层事务的提交而提交。

事务的提交 最终 是调用 connect.commit 函数提交事务。

在事务提交前后 会触发TransactionSynchronuzation 钩子函数。进行资源释放操作。

mybatis 会在beforeCommit 中 执行Sqlsession commit

6 一些细节

  1. 方法上面 @Transaction 注解 会覆盖 类上面的 @Transaction注解信息。是完全的覆盖,而不是 部分覆盖,就是说 ,如果类上设置了 事务超时时间 为 10秒,但是 方法上面没有设置事务超时时间,那么 最终 事务 就是没有超时时间,并不会 采用 类上面的 超时时间。
  1. 事务隔离级别 和 超时时间 只能作用于 一个 新事务,也就是说 ,当内部事务参与到一个已经存在的事务中时,事务隔离级别 和 超时时间将会被忽略。因为 内部事务 是参与到外层事务。

  2. 事务rollbackFor 的 含义是 默认异常 或 指定异常,就是说,默认回滚异常时 runtimeException 或 Error 或 自己指定的异常。

你可能感兴趣的:(Spring 事务实现分析)