一、概述

事务是多个操作在逻辑上构成一组操作,要么全部执行,要么全部不执行.

Spring 事务本质:对数据库事务的包装

二、事务四大特性( ACID )

  • 1. Atomicity(原子性)

    • 事务是一个不可分割的整体,事务中的操作要么全部成功,要么全部失败
  • 2. Consistency(一致性)

    • 在一个事务执行之前和执行之后,数据库都必须处于一致性状态
    • 原子性、隔离性、持久性 同时满足来保证一致性
  • 3. Isolation(隔离性)

    • 一个事务的执行不应该影响其他事务的执行,事务与事务之间要做数据隔离
  • 4. Durability(持久性)

    • 一个事务一旦被提交,它对数据库中数据的改变就是永久性的

事务的最终目的:数据一致性

分布式事务最终目的: 数据的最终一致性

三、事务五种隔离级别

  • 1. DEFAULT(默认选项)
  • 2. READ_UNCOMMITTED(未提交读)
  • 3. READ_COMMITTED(已提交读)
  • 4. REPEATABLE_READ(可重复读)
  • 5. SERIALIZABLE(串行化、序列化)

四、事务七大传播行为

前置说明

若A()、B()方法都启用了事务

  1. A()方法的事务,称为:当前事务(外部事务)
  2. B()方法的事务,称为:嵌套事务(内部事务)

1. REQUIRED

若存在当前事务 则加入当前事务;

若当前没有事务 则开启一个新事务

2. SUPPORTS

如果存在当前事务 则加入当前事务;

若当前没有事务 则以非事务方法执行

3. MANDATORY

如果存在当前事务 则加入当前事务;

若当前没有事务 则抛出异常

4. REQUIRES_NEW

总是新开启一个事务

若当前存在事务时, 将当前事务挂起并新开启一个事务, 此时内部事务的回滚/异常 会影响外部事务, 外部事务不会影响内部事务;

5. NOT_SUPPORTED

表示以非事务的方式来运行, 若存在当前事务, 则把当前事务挂起;

6. Never

表示不以事务的方式运行, 若当前存在事务, 则抛出异常

7. Nested

若没有外部事务 就新建一个事务,若有外部事务,则嵌套在当前事务中执行;

外部事物的回滚/异常 会影响内部事务, 内部事务的回滚不会影响外部事务

五、事务失效场景

Spring 事务在以下这些场景下,会失效

  • 事务方法未被Spring管理
  • 方法使用final类型修饰
    Spring事务底层使用了AOP,也就是通过JDK动态代理或者cglib,帮我们生成了代理类,在代理类中实现的事务功能。但如果某个方法用final修饰了,那么在它的代理类中,就无法重写该方法,从而无法添加事务功能。这种情况事务就会在Spring中失效。
    💡Tips: 如果某个方法是static的,同样无法通过动态代理将方法声明为事务方法。
  • 非public方法
    非public的方法AOP也无法做代理增强
  • 调用本类的方法
    spring的事务实现是使用了代理类来实现,假设TestService类中a()方法调用本地方法 b(),就算b()方法加了@transactional注解, 但是实际上并没有走TestService的代理类,所以事务会失效
  • 抛出捕捉非运行时异常
  • 数据库不支持事务
  • 项目未配置开启事务
  • 多线程,事务会失效
    Spring的事务是通过ThreadLocal来保证线程安全的,事务和当前线程绑定,多个线程自然会让事务失效

六、Spring 事务源码分析

  • Spring 提供了对数据库的事务包装
  • Spring 事务 = Spring AOP + 数据库事务

1. Spring事务处理基本流程

  • 1). 在类和方法上添加@Tranactional
  • 2). Spring在启动时,会去解析生成相关的Bean
  • 3). 最后Spring调用MySQL ( 或其他数据库 ) API,完成事务处理

2. 注解 @Transactional

作用

  • 标识在对应的方法上,告知 Spring 这个目标方法需要被代理
  • 携带事务管理需要的一些属性信息
Spring Boot
TransactionAutoConfiguration

1). TransactionAutoConfigurationSpring Boot 关于事务的自动配置类

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({PlatformTransactionManager.class})
@AutoConfigureAfter({JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class})
@EnableConfigurationProperties({TransactionProperties.class})
public class TransactionAutoConfiguration {
  • @Configuration

    • 配置类
  • @ConditionalOnClass(PlatformTransactionManager.class)

    • 当前类路径下存在 PlatformTransactionManager.class 时该配置生效
  • @AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class,Neo4jDataAutoConfiguration.class })

    • 在 JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class,Neo4jDataAutoConfiguration.class 之后才解析该类.
  • @EnableConfigurationProperties(TransactionProperties.class)

    • 可通过以下2个属性来配置:

      • spring.transaction.defaultTimeout–> 配置事务的默认超时时间
        spring.transaction.rollbackOnCommitFailure–> 配置是否在事务提交失败时回滚

2). 其中两个内部类

a. EnableTransactionManagementConfiguration

public class TransactionAutoConfiguration {
    此处省略.....
    
    // 标注为配置类
    @Configuration(proxyBeanMethods = false) 
    // beanFactory 中存 TransactionManager 类型的bean时该配置生效
    @ConditionalOnBean({TransactionManager.class
    // beanFactory 不存在 AbstractTransactionManagementConfiguration 类型的bean时生效
    @ConditionalOnMissingBean({AbstractTransactionManagementConfiguration.class})
    public static class EnableTransactionManagementConfiguration {
        ....
        
        @Configuration(proxyBeanMethods = false)
        // TransactionManagement, proxyTargetClass = true,表示是使用cglib进行代理
        @EnableTransactionManagement(proxyTargetClass = true)
        // 其中, 当配置有 spring.aop.proxy-target-class 时,
        // havingValue = true 代表当 spring.aop.proxy-target-class 的value 值 为 true, 则该代理生效
        @ConditionalOnProperty(
            prefix = "spring.aop",
            name = {"proxy-target-class"},
            havingValue = "true",
            matchIfMissing = true
        )
        public static class CglibAutoProxyConfiguration {
            public CglibAutoProxyConfiguration() {
            }
        }
        
        
        
        @Configuration(proxyBeanMethods = false)
        // TransactionManagement, proxyTargetClass = false,表示是面向接口代理, 使用JDK的实现
        @EnableTransactionManagement(proxyTargetClass = false)
        // 其中, 当配置有 spring.aop.proxy-target-class 时,
        // havingValue = true 代表当 spring.aop.proxy-target-class 的value 值 为 false, 则该代理生效
        // 默认使用的该实现进行代理
        @ConditionalOnProperty(
            prefix = "spring.aop",
            name = {"proxy-target-class"},
            havingValue = "false",
            matchIfMissing = false
        )
        public static class JdkDynamicAutoProxyConfiguration {
            public JdkDynamicAutoProxyConfiguration() {
            }
        }
        
    }
}

因此,在默认情况下, EnableTransactionManagementConfiguration 生效的是 JdkDynamicAutoProxyConfiguration.

b. TransactionTemplateConfiguration

public class TransactionAutoConfiguration {
    此处省略.....
    
    @Configuration(proxyBeanMethods = false)
    // PlatformTransactionManager类型的bean存在并且当存在多个bean时指定为Primary
    // 的PlatformTransactionManager存在时,该配置类才进行解析
    @ConditionalOnSingleCandidate(PlatformTransactionManager.class)
    public static class TransactionTemplateConfiguration {
        public TransactionTemplateConfiguration() {
        }

        // 当 beanFactory 中不存在 TransactionOperations 类型的bean时,
        // 注册一个id为 transactionTemplate,类型为 TransactionTemplate 的 bean
        // TransactionTemplate 实现了 TransactionOperations
        @Bean
        @ConditionalOnMissingBean({TransactionOperations.class})
        public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
            return new TransactionTemplate(transactionManager);
        }
    }
}

由于 TransactionAutoConfiguration 是在 DataSourceTransactionManagerAutoConfiguration 之后才被解析处理的, 而在DataSourceTransactionManagerAutoConfiguration 中配置了 transactionManager,因此, TransactionTemplateConfiguration 会被处理.

**3). 以上内部类中使用到的@EnableTransactionManagement 注解** ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a85277135c.png) ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a86d8a2164.png) 其中引入了 `TransactionManagementConfigurationSelector.class` ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a879e95053.png) 其中默认走 PROXY 方法部分, 注册 `AutoProxyRegistrar` 和 `ProxyTransactionManagementConfiguration` - `AutoProxyRegistrar` ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a8ccb79558.png) ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a8fb60498f.png) ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a90b15c834.png) 以上向容器注册, 这里都是 `AOP 的源码` 部分了 - `ProxyTransactionManagementConfiguration`: > 在这个类中 `transactionAdvisor` 方法的实现, 传入的参数有两个 > > 1. `TransactionAttributeSource` > 2. `TransactionInterceptor` > > 下面分别介绍这两个类的作用 ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a92fce7ad4.png) - ①`TransactionAttributeSource` 实现 > TransactionAttributeSource 类主要用于处理解析 @Transactional 注解相关的元数据 ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a9cb2a2d95.png) 进入方法, 其中调用了 父类方法 ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a9ccd143b5.png) 进入父类方法 `this(true)` ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a9d46e89b0.png) 进入类 `SpringTransactionAnnotationParser`, 其中有 `parseTransactionAnnotation(AnnotatedElement element)` 方法 ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a9e1dc8679.png) 接着进入 `parseTransactionAnnotation(attributes)`方法 ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a9f00ac910.png) - ②`TransactionInterceptor` 实现 > TransactionInterceptor 类是事务相关的拦截器的一些实现, 当有事务相关逻辑的时候, Spring AOP 会调用该类型的拦截器做处理 ![](https://img.pelycloud.com/pelyblog/2023/12-26/658aa40257bec.png) 当AOP执行到该拦截器的时候, 会调用此处的 `invoke` 方法,接着调用了父类的 `invokeWithinTransaction()` 方法, ![](https://img.pelycloud.com/pelyblog/2023/12-26/658aa8040238c.png) 查看其 `invokeWithinTransaction()`方法, 该方法为 父类 `TransactionAspectSupport` 抽象类的实现 ```java @Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class targetClass, final InvocationCallback invocation) throws Throwable { // 获取事务注解中的属性(获取@Transactional注解定义的的一些属性(包括隔离级别,传播机制等)) TransactionAttributeSource tas = getTransactionAttributeSource(); // 封装成TransactionAttribute final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); // 事务管理器(默认创建一个DataSourceTransactionManager,包含数据库信息等) final TransactionManager tm = determineTransactionManager(txAttr); if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) { ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> { if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) { throw new TransactionUsageException( "Unsupported annotated transaction on suspending function detected: " + method + ". Use TransactionalOperator.transactional extensions instead."); } ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType()); if (adapter == null) { throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " + method.getReturnType()); } return new ReactiveTransactionSupport(adapter); }); return txSupport.invokeWithinTransaction( method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm); } // 事务包装成PlatformTransactionManager对象 PlatformTransactionManager ptm = asPlatformTransactionManager(tm); // 获取目标方法的方法名(就是切点) final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); // 如果是声明式事务 [IN] if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) { // 根据事务管理器、事务属性、事务名称创建事务信息对象(这个很重要,包含有事务和数据库连接等相关信息)>> TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification); Object retVal; try {// [STOP] [+] [IN] // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. // 调用目标方法,访问数据库和业务逻辑处理等(到proceed()方法调用目标方法) retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // 回滚事务(出现异常) completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { // 事务执行完成后,将上一个事务的信息,恢复现场(就是事务挂起后的恢复 没有挂起则不执行恢复) cleanupTransactionInfo(txInfo); } if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) { // Set rollback-only in case of Vavr failure matching our rollback rules... TransactionStatus status = txInfo.getTransactionStatus(); if (status != null && txAttr != null) { retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status); } } // 提交事务 commitTransactionAfterReturning(txInfo); return retVal; } 省略... } ``` 该方法就是处理事务的完整逻辑, 根据注释可明显的辨别该实现就是一个 AOP 环绕通知的实现: ``` 大致逻辑 1.处理数据库及相关事务信息, 关闭事务自动提交 2.调用原方法 3.有异常回滚/没异常提交事务 ``` ##### Spring > `@EnableTransactionManagement` > > ![](https://img.pelycloud.com/pelyblog/2023/12-26/658a9fe4bf58c.png) 参考以上 SpringBoot 中`@EnableTransactionManagement`源码部分: [@EnableTransactionManagement ](#EnableTransactionManagement) ### 3. Spring 事务核心源码 ![](https://img.pelycloud.com/pelyblog/2023/12-26/658aa2a3a59c2.png) ### 4. Spring 事务调用完整流程图 [流程图下载链接](https://pan.pelycloud.com/d/%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99/Spring/A_5.Spring%E4%BA%8B%E5%8A%A1%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B%E5%9B%BE.svg) ![Spring事务原理分析完整流程图](https://pan.pelycloud.com/d/%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99/Spring/A_5.Spring%E4%BA%8B%E5%8A%A1%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B%E5%9B%BE.svg)
最后修改:2023 年 12 月 26 日
如果觉得我的文章对你有用,请点个赞吧~