Spring事务分析

Spring事务概念和用法tips:

http://sishuok.com/forum/blogPost/list/2502.html数据库事务
http://sishuok.com/forum/blogPost/list/2506.html(不推荐)编程事务:两种,(重点了解)事务定义:隔离级别和传播行为等
http://sishuok.com/forum/blogPost/list/2508.html声明事务

Spring事务处理应用场景

  1. 通过声明式事务处理,将事务处理的过程和业务代码分离出来
  2. 应用在选择数据源时可能会采取不同的方案,Spring在应用和具体数据源之间,搭建一个中间平台,通过这个中间平台,解耦应用和具体数据源之间的绑定,这样应用在使用不同的数据源时,可以做到事务处理的即开即用,提供了一种一致的方式

Spring事务原理

Spring事务类图

Spring事务分为对一个数据库操作的事务(对JDBC事务的封装)和对多个数据库操作的分布式事务

本文讨论的都是声明式事务,首先看下Spring事务处理的设计类图:

Spring事务分析_第1张图片

从类图中可以发现,ProxyConfig就是在前面Spring Aop原理分析(一)提到的父类,不难发现,Spring声明式事务就是用Aop来实现的,我们重点分析以下几个类

  • ProxyConfig:代理的通用类,换句话说,想要在Spring中实现代理,就要继承该类,可以想象,Spring很多组件都是通过Spring的Aop代理的
  • TransactionProxyFactoryBean:可以生成Proxy代理对象
    • FactoryBean:在这再复习一下,采用工厂方法模式,具体工厂可以实现该方法,调用getObject方法获取具体事例
    • InitializingBean:实现路径AbstractAutowireCapableBeanFactory.initializeBean->invokeInitMethods->InitializingBean.afterPropertiesSet(http://www.2cto.com/kf/201310/251778.html),该接口的方法会在Bean初始化时被调用,主要作用是在调用初始化方法之前,对bean进行一些额外的配置,在这配置指的是事务
  • TransactionInterceptor:事务拦截器,通过前面Aop的分析可知,每个代理对象都需要一个Invocationhandler,先执行通知,然后执行目标方法,类TransactionInterceptor等价于Invocationhandler
  • PlatformTransactionManager:事务处理器,有了一个对不同数据源事务操作的管理中心

通过以上信息,对整个事务的流程以及所使用到的类都很清楚,模仿着事务组件,也可以开发出我们自己的组件

Spring声明式事务设计原理与基本过程

事务处理拦截器的配置

Spring事务分析_第2张图片
该时序图已经很清楚说明了事务处理拦截器的配置(TransactionProxyFactoryBean.createMainInterceptor),具体来说,这里涉及的类是TransactionAttributeSourceAdvisor,它是一个Aop通知器,通过TransactionInterceptor为通知器设置拦截器

事务处理配置的读入

在声明式事务处理中,通过对目标对象的方法调用进行拦截实现,这个拦截通过Aop发挥作用。在Aop中,对于拦截的启动,首先需要对方法调用是否需要拦截进行判断,而判断的依据是那些在TransactionProxyFactoryBean中为目标对象设置的事务属性。也就是说,需要判断当前的目标方法调用是不是一个配置好的并且需要进行事务处理的方法调用。

以下代码是事务处理配置的读入的实现,配置的是一个NameMatchTransactionAttributeSource对象

TransactionProxyFactoryBean
    public void setTransactionAttributes(Properties transactionAttributes) {
        this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
    }

在应用调用目标方法的时候,因为这个目标方法已经被TransactionProxyFactoryBean代理,所以TransactionProxyFactoryBean需要判断这个目标方法是否是事务方法,典型调用过程如图:
Spring事务分析_第3张图片

事务拦截器的设计与实现

在完成以上的准备工作以后,经过TransactionProxyFactoryBean的Aop的包装,此时如果对目标对象进行方法调用,起作用的实际上是一个Proxy代理对象,对目标对象方法的调用,不会直接作用在TransactionProxyFactoryBean设置的目标对象上,而会被设置的事务拦截器拦截。TransactionProxyFactoryBean作为一个FactoryBean,对这个Bean的对象的引用是通过调用TransactionProxyFactoryBean .getObject方法来得到的,如果还有印象,大家会注意到一个重要的involve方法,这个invoke方法是Proxy代理对象的回调方法,即在事务处理拦截器TransactionInterceptor.invoke中,其过程是

  • 首先,获取事务处理配置
  • 然后,获取事务处理器PlatformTransactionManager,实现事务的创建、提交、回滚操作,对于Spring而言,事务的管理实际上是通过一个TransactionInfo对象来完成的,在该对象中,封装了事务的配置信息、事务的状态信息等

下面是事务提交的时序图:

Spring事务处理设计与实现

事务创建和提交

根据上一节事务提交的时序图可知,TransactionAspectSupport.createTransactionIfNecessary方法作为事务创建的入口,

  • 首先会向事务处理器AbstractPlatformTransactionManager执行getTransaction,创建事务对象,对于不同的事务处理器需要对事务的情况作出不同的处理,返回一个TransactionStatus
  • 然后TransactionStatus设置到TransactionInfo中去,同时将TransactionInfo和当前线程绑定(将TransactionInfo设置到ThreadLocal中)

再看createTransactionIfNecessary方法调用的时序图:

事务隔离级别和传播行为

事务的隔离级别和传播行为都定义在该类TransactionDefinition中
在Spring中,AbstractPlatformTransactionManager.getTransaction是对事务隔离级别和传播行为的实现,细节就不再研究了,不同事务处理器例如DataSourceTransactionManager、JpaTransactionManager、DataSourceTransactionManager会处理不同的事务细节,包括事务的提交、事务的挂起、事务的回滚等

    @Override
    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)) {
            // Existing transaction found -> check propagation behavior to find out how to behave.
            return handleExistingTransaction(definition, transaction, debugEnabled);
        }

        // Check definition settings for new transaction.
        if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
            throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
        }

        // No existing transaction found -> check propagation behavior to find out how to proceed.
        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.
            boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
            return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
        }
    }

你可能感兴趣的:(spring,编程,源码,互联网,事务)