spring的事务切面(上)

一个问题
spring的事务切面(上)
在插入操作的事务最后抛出Exception异常,能否插入成功?
Spring事务处理的设计概览
spring的事务切面(上)

Spring的事务处理模板中的类层次接口
真正处理事务的是TransactionInterceptor,PlatformTransactionManager,AbstractionTransactionManager以及DataSourceTransactionManager,其他的类用来读取配置、加载通知以及实现织入。
事务处理拦截器的设计与实现
TransactionInterceptor类继承自MethodInterceptor,所以调用该类是从其invoke方法开始的。这个invoke()方法是Proxy代理对象的回调方法,在调用Proxy对象的代理方法时触发这个回调。在事务处理拦截器TransactionInterceptor中,invoke方法的实现如下图。可以看到,其过程时,首先获得调用方法的事务处理配置;在得到事务处理配置之后,会取得配置的PlatformTransactionManger,由这个事务处理器来实现事务的创建、提交、回滚操作。PlatformTransactionManger事务处理器是在Ioc容器中配置的,比如大家已经很熟悉的DataSourceTransactionManger和HibernateTransactionManager。有了这一系列的具体事务处理器的配置,在Spring事务处理模块的统一管理下,由这些具体的事务处理器来完成事务的创建、提交、回滚等底层的事务操作。
spring的事务切面(上)
第一步是得到代理的目标对象,并将事务属性传递给目标对象。
spring的事务切面(上)
采用非回调的方法来对事务进行提交
271.读取事务的配置属性,通过TransactionAttributeSource对象取得
272.根据TransactionProxyFactoryBean的配置信息获得具体的事务处理器
273.构造方法唯一标识(类.方法 如service.impl.UserServiceImpl.save)
275.这里区分不同类型的PlatformTransactionManger,因为他们的调用方式不同,对CallbackPreferringPlatformTransactionManger来说,需要回调函数来实现事务的创建和提交;对于非CallbackPreferringPlatformTransactionManger来说,不需要通过回调函数来实现事务的和提交,像DataSourceTransactionManger就不是CallbackPreferringPlatformTransactionManger,不需要通过回调的方式来使用。
277.这里创建事务,同时把创建事务过程中得到的信息放到TransactionInfo中去,TransactionInfo是保存当前事务状态的对象。
282.这里的调用使处理沿着拦截器链进行,使最后目标对象的方法得到调用。
286.如果在事务处理方法调用中出现了异常,事务处理如何进行需要根据具体的情况考虑回滚或者提交。Spring默认只对RuntimeException以及Error执行回滚
spring的事务切面(上)
290.这里把与线程绑定的TransactionInfo设置为oldTransactionInfo
292.这里通过事务处理器来对事务进行提交。
spring的事务切面(上)
spring的事务切面(上)
采用回调的方法来使用事务处理器。
312.RuntimeException会导致事务回滚
321.正常的返回,导致事务提交
流程梳理:
在调用代理的事务方法时,因为前面已经完成了一系列AOP配置,对事务方法的调用,最终启动TransactionInterceptor拦截器的invoke方法。在这个方法中,首先会读取该事务方法的事务属性配置,然后根据事务属性配置以及具体事务处理器的配置来决定采用哪一个事务处理器,这个事务处理器实际上是一个PlatformTransactionManger。在决定好具体的事务处理器之后,会根据事务的运行情况和事务配置来决定是不是需要创建新的事务。对于Spring而言,事务的管理实际上是通过一个TransactionInfo对象来完成的,在该对象中,封装了事务对象和事务处理的状态信息,这是事务处理的抽象。在这一步完成之后,会对拦截器链进行处理,因为有可能在该事务对象中还配置了除事务处理AOP之外的其他拦截器。在结束对拦截器链处理之后,会对TransactionInfo中的信息进行更新,以反映最近的事务处理情况,在这个时候,也就是完成了事务提交的准备,通过调用事务处理器PlatformTransactionManger的commitTransactionAfterReturning方法来完成事务的提交。这个提交的处理过程已经封装在PlatformTransactionManger的事务处理器中了,而与具体数据源相关的处理过程,最终委托给相关的具体事务处理器来完成,比如DataSourceTransactionManager、HibernateTransactionManager等。
spring的事务切面(上)
事务提交的时序图
在这个invoke()方法的实现中,可以看到整个事务处理在AOP拦截器中实现的全过程。同时,它也是Spring采用AOP封装事务处理和实现声明式事务处理的核心部分。这部分实现,是一个桥梁,它胶合了具体的事务处理和Spring AOP框架,可以看成是一个Spring AOP应用,在这个桥梁搭建完成之后,Spring事务处理的实现就开始了。
Spring事务处理的编程式使用(模型)
spring的事务切面(上)
在编程式使用事务处理的过程中,利用DefaultTransactionDefinition对象来持有事务处理属性。同时,在创建事务的过程中得到一个TransactionStatus对象,然后通过直接调用transactionManager的commit()和rollback()方法来完成事务处理。在这个编程式使用事务管理的过程中,没有看到框架特性的使用,非常简单和直接,很好地说明了事务管理的基本实现过程,以及在Spring事务处理实现中涉及一些主要的类,比如TransactionStatus、TransactionManger等,对这些类的使用与声明式事务处理的最终实现是一样的。
事务的创建
作为声明式事务处理实现的起始点,需要注意TransactionInterceptor拦截器的invoke回调中使用的createTransactionIfNecessary方法,这个方法是在TransactionIntercepor的基类TransactionAspectSupport中实现的。
在createTransactionIfNecessary方法的调用中,会向AbstractTransactionManger执行getTransaction(),这个获取Transaction事务对象的过程,在AbstractTransactionManger实现中需要对事务的情况做出不同的处理,然后,创建一个TransactionStatus,并把这个TransactionStatus设置到对应的TransactionInfo中去,同时将TransactionInfo和当前的线程绑定,从而完成事务的创建过程。
spring的事务切面(上)
调用createTransactionIfNecessary的时序图
spring的事务切面(上)
445.从外部参数读取事务方法调用的事务配置属性,以及使用的PlatformTransactionManger
449.如果没有指定名字,使用方法唯一标识来作为事务名
458.这个TransactionStatus封装了事务执行的状态信息
461.这里使用了定义好的事务方法的配置信息,事务创建由事务处理器来完成,同时返回TransactionStatus来记录当前的事务状态,包括已经创建的事务
470.准备TransactionInfo。TransactionInfo对象封装了事务处理的配置信息以及TransactionStatus
spring的事务切面(上)
491.这里为TransactionInfo设置TransactionStatus,这个TransactionStatus很重要,它持有管理事务处理需要的数据,比如,transaction对象就是由TransactionStatus来持有的。
504.这里把当前的TransacctionInfo与线程绑定,同时在TransactionInfo中由一个变量来保存以前的TransactionInfo,这样就持有了一连串与事务处理相关的TransactionInfo,虽然不一定需要创建新的事务,但是总会在请求事务时创建TransactionInfo。
具体的事务创建可以交给事务处理器来完成。在事务的创建过程中,已经为事务的管理做好了准备,包括记录事务处理状态,以及绑定事务信息和线程等。createTransactionIfNecessary()方法中的tm.getTransaction(txAttr)调用触发,生成一个TransactionStatus对象,封装了底层事务对象的创建。可以看到,AbstractionPlatformTransactionManager提供了创建事务的模板。AbstractPlatformTransactionManager会根据事务属性配置和当前进程绑定的事务信息,对事务是否需要创建,怎样创建进行一些通用的处理,然后把事务创建的底层工作交给具体的事务处理器完成。尽管具体的事务处理器完成事务创建的过程各不相同,但是不同的事务处理器对事务属性和当前进程事务信息的处理都是相同的。
spring的事务切面(上)
341.这个doGetTransaction()是抽象函数,Transaction对象的取得由具体的事务处理器实现,比如DataSourceTransactionManager
344.缓存debug标志位
346.如果没有设置事务属性,那么使用默认的事务属性DefaultTransactionDefinition。关于这个DefaultTransactionDefinition,在前面编程式使用事务处理的时候遇到过。这个DefaultTransactionDefinition的默认事务处理属性是:propagationBehivor = PROPAGATION_REQUIRED;isolationLevel=ISOLATION_DEFAULT;timeout=TIMEOUT_DEFAULT;readOnly=false
351.检查当前线程是否已经存在事务,如果已经存在事务,那么需要根据在事务属性中定义的事务传播属性配置来处理事务的产生(handleExistingTransaction())。
353.这里对当前线程中已经有事务存在的情况进行处理,结果封装在TransactionStatus中。
357.检查事务属性中timeout的设置是否合理
spring的事务切面(上)
361.当前没有事务存在,这是需要根据事务属性设置来创建事务,这里会看到对事务传播属性设置的处理,比如mandatory、required、required_new、nested等。
377.这里是创建事务的调用,构造transaction,包括设置ConnectionHolder、隔离级别、timeout。如果是新连接,绑定到当前线程。由具体的事务处理器完成,比如HibernateTransactionManager和DataSourceTransactionManager等。在后面DataSourceTransactionManager的说明中会进一步讲解。
379.返回TransactionStatus封装事务执行情况,默认getTransactionSynchronization = SYNCHRONIZATION_ALWAYS,所以在这种情况下,newSynchronization为true
391.创建TransactionStatus,但是没有transaction对象,因为在newTransactionStatus中对应于transaction的参数是null
流程梳理:
事务创建的结果是生成一个TransactionStatus对象,通过这个对象来保存事务处理需要的基本信息,这个对象与前面提到过的TransactionInfo对象联系在一起,TransactionStatus是TransactionInfo的一个属性,然后会把TransactionInfo保存在ThreadLocal对象里,这样当前线程可以通过ThreadLocal对象取得TransactionInfo,以及与这个事务对应的TransactionStatus对象,从而把事务的处理信息与调用事务方法的当前线程绑定起来。
spring的事务切面(上)
528.这里判断是不是新事务,如果是新事务,那么需要把事务属性存放到当前线程中。TransactionSynchronizationManager维护一系列的ThreadLocal变量来保持事务属性,比如并发事务隔离级别,是否有活跃的事务等。
530.这里是把结果记录在DefaultTransactionStatus中返回。
spring的事务切面(上)

新事务的创建是比较好理解的,这里需要根据事务属性配置进行创建。所谓创建,首先是把创建工作交给具体的事务处理器来完成,比如DataSourceTransactionManager,把创建的事务对象在TransactionStatus中保存下来,然后将其他的事务属性和线程ThreadLocal变量进行绑定。