Transaction

[TOC]

Transactional

简介

Spring事务

源码分析

从事务如何生效开始

大家都知道Spring的事务是基于AOP完成的,那么我们就从这个AOP说起。

假设一个例子:

类A:

// 省去Bean管理
public class A {
    
    @Transactional
    public void test(){
    }
    
}

调用类:

那么此时调用a.test(),会被代理一层,其中a是代理类,代理类很长,但是目的是代理方法,我们只要关注被代理的方法即可,即:test()。

下面为省略后的代理类,全部源码代理类如何获得?):

通过上述代理类,我们得知了:代理类主要目的是为了执行org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept方法,那么接下来我们直接从这个方法往下看:

从代理类开始,整理下调用链路:

上图中主要展示了AEnhancerBySpringCGLIBEnhancerBySpringCGLIB21771092、DynamicAdvisedInterceptor、CglibMethodInvocation、TransactionInterceptor这4个类:

  • AEnhancerBySpringCGLIBEnhancerBySpringCGLIB21771092

    Aop生成的代理类

  • DynamicAdvisedInterceptor

    General purpose AOP callback. Used when the target is dynamic or when the proxy is not frozen.

    通用 AOP 回调。当目标为动态的或者代理不被禁用时使用。为CglibAopProxy的静态内部类。

  • CglibMethodInvocation

    Implementation of AOP Alliance MethodInvocation used by this AOP proxy.

    此 AOP 代理使用的 AOP Alliance MethodInvocation 的实现。为CglibAopProxy的静态内部类。

  • TransactionInterceptor

    AOP Alliance MethodInterceptor for declarative transaction management using the common Spring transaction infrastructure (PlatformTransactionManager). Derives from the TransactionAspectSupport class which contains the integration with Spring's underlying transaction API. TransactionInterceptor simply calls the relevant superclass methods such as invokeWithinTransaction in the correct order.

    AOP Alliance MethodInterceptor 使用通用 Spring 事务基础结构 (PlatformTransactionManager) 进行声明式事务管理。 派生自 TransactionAspectSupport 类,该类包含与 Spring 的底层事务 API 的集成。 TransactionInterceptor 只是以正确的顺序调用相关的超类方法,例如 invokeWithinTransaction。

最终调用org.springframework.transaction.interceptor.TransactionInterceptor#invoke,看到这里终于开始有事务的影子了,我们继续往下看:

这边的代码大家一看就懂,无非就是获取目标Class对象,然后继续调用invokeWithinTransaction,在继续往下看之前,我们先看下类图:

TransactionUml
  • TransactionAspectSupport:实现了Spring事务基础架构,为任何后续的实现提供了基础。

TransactionInterceptor继承TransactionAspectSupport,而invokeWithinTransaction是TransactionAspectSupport的方法。下面,我们继续分析invokeWithinTransaction方法:(这个方法有点长,我将大致的代码思路备注在源码中)

看完了上述的这个方法,对整个事务的流程也有个大致了解,无非就是那套:

此时,我们有以下几个疑问:

  • 事务有传播性,这是如何实现的?

  • 事务是数据库实现的,开启事务还得依赖数据库,那么操作数据库开启事务的代码在哪里?

  • 数据库有很多种,如何区分的呢?

带着问题我们先看开启事务这部分的源码TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

首先来看下获取事务,方法位于AbstractPlatformTransactionManager中:

从上述方法中,我们发现,Spring的事务传播性在getTransaction得到实现,下面继续看开启事务方法startTransaction

很明显doBegin是具体开启事务的入口,doBegin为抽象类AbstractPlatformTransactionManager的抽象方法,我们看看Javadoc的注释:

原文翻译如下:

根据给定的事务定义开始一个具有语义的新事务。不必关心应用传播行为,因为这已经由这个抽象管理器处理了。 当事务管理器决定实际开始一个新事务时,将调用此方法。要么之前没有任何事务,要么之前的事务已被暂停。 一个特殊的场景是没有保存点的嵌套事务:如果 useSavepointForNestedTransaction() 返回“false”,则将在必要时调用此方法以启动嵌套事务。在这样的上下文中,将有一个活动事务:此方法的实现必须检测到这一点并启动一个适当的嵌套事务。

白话文:

挑重点看,原文中说会开启一个新的事务,切无需关心底层实现。大致可以猜到此接口将会由不同的事务管理器进行实现,且都内聚了数据库开启事务的具体操作。

大家都知道,咱们用的事务管理器最常见的属DataSourceTransactionManager,下面就以它的实现为例,来继续分析:

核心逻辑 Connection newCon = obtainDataSource().getConnection();,数据库连接的获取就在此处,由于接口DataSource的实现较多,我们不再往下继续展示源码逻辑。

看完了源码,为了更清晰的展示事务的核心逻辑,我们用代码调用链画出源码逻辑:

Tips: 假设数据库连接池选用Druid实现,其他连接池实现大抵相似。

上图中主要展示了TransactionAspectSupport、DataSourceTransactionManager、DruidDataSource、DataSourceTransactionObject这4个类:

  • TransactionAspectSupport

    主要实现了事务的Aop逻辑,不涉及事务实现的细节

  • DataSourceTransactionManager

    继承了AbstractPlatformTransactionManager,实现了接口PlatformTransactionManager,主要封装了事务实现细节,但与数据库的连接等操作,依赖于接口DataSource的实现。

    • AbstractPlatformTransactionManager

      Abstract base class that implements Spring's standard transaction workflow, serving as basis for concrete platform transaction managers

      实现Spring的标准事务工作流的抽象基类,用作具体平台事务管理器的基础

    • PlatformTransactionManager

      This is the central interface in Spring's transaction infrastructure. Applications can use this directly, but it is not primarily meant as API: Typically, applications will work with either TransactionTemplate or declarative transaction demarcation through AOP.

      这是Spring事务基础架构中的中央接口。应用程序可以直接使用它,但是它并不是主要用于API:通常,应用程序可以通过Transaction模板或通过AOP进行声明式事务划分来使用。

    当然,Spring中肯定不会仅仅有DataSourceTransactionManager这一个实现,她还有HibernateTransactionManager、JpaTransactionManager等等实现,我们大致看下类图,至于各自实现的细节,不在本篇文章中描述(下图中也是部分):

    PlatformTransactionManagerImpl
  • DataSourceTransactionObject

    为DataSourceTransactionManager的静态内部类,被DataSourceTransactionManager所使用,为了保存Connection并操作其方法。

  • DruidDataSource

    Druid数据源,继承了DruidAbstractDataSource,实现了接口DataSource,封装了和数据库的交互逻辑。

    同样,DataSource的实现有很多,我们挑几个常见的,看下类图:

    DataSource

到这里,回顾下我们的问题,看看是不是都得到了解答。

此时,我们有以下几个疑问:

  • 事务有传播性,这是如何实现的?

  • 事务是数据库实现的,开启事务还得依赖数据库,那么操作数据库开启事务的代码在哪里?

  • 数据库有很多种,如何区分的呢?

  • 事务有传播性,这是如何实现的?

    方法为AbstractPlatformTransactionManager.getTransaction,根据事务定义的传播级别,来做判断处理。

  • 事务是数据库实现的,开启事务还得依赖数据库,那么操作数据库开启事务的代码在哪里?

    答案:接口PlatformTransactionManager的抽象实现AbstractPlatformTransactionManager,主要封装了事务的工作流,其中开启事务的核心入口doBegin为抽象方法,交由子类实现。以常见的DataSourceTransactionManager为例,doBegin方法中依赖了DataSource接口的实现,通过DataSource.getConnection()获取数据库连接Connection对象,并做一系列的数据库事务开启操作。

  • 数据库有很多种,如何区分的呢?

    答案:Spring将事务的实现做了抽象。针对事务的工作流,提供了灵活的接口和抽象类,比如:接口PlatformTransactionManager、抽象基类AbstractPlatformTransactionManager,通过实现、继承来完成不同数据库的差异性。针对数据库的交互细节,提供了接口DataSource的定义,不同的数据源都可以进行自己的实现,来完成数据源的实现。

到此,你是不是对Spring事务的实现有所了解了呢?

最后,附上前辈画的一张图,辅助大家对Spring事务源码的理解:

TransactionInfrastructure

Last updated