Spring3.1.0实现原理分析(二十二).Dao事务分析之事务管理器DataSourceTransactionManager...

       大家好,开篇先来谈谈spring事务的优点吧,即spring事务的存在价值。首先它提供了非侵入式编码的事务实现,这个是通过aop实现的,具体的实现过程之前也写博客分析了。

       另外,spring还提供了一套标准的事务管理工作流程。简单的说,事务管理一共可分为三个步骤,分别是初始化事务、提交事务、回滚事务,然后每个步骤又可细分为若干小步骤。spring事务工作流相当于为用户屏蔽了具体orm框架的底层处理逻辑,基于spring开发的程序,即便更换了orm框架,即便从本地事务切换到全局事务,也只需要简单的更改配置,选用合适的事务管理器,基本不会修改代码,这就是spring事务另一个优点。

     

       Spring的PlatformTransactionManager是事务管理的顶层接口,其中定义的三个方法对应的就是上述的三个步骤,然后AbstractPlatformTransactionManager抽象类给出了三个步骤的具体实现。当然,AbstractPlatformTransactionManager也留下了几个未实现的抽象方法,具体有“创建事务对象”,“开始事务”,“执行提交”,“执行回滚”,这几个抽象方法的实现跟具体的orm框架(如:mybatis,hibernate)或事务特性(如:本地事务,全局事务)有关。比如今天要介绍的主角DataSourceTransactionManager,它实现了上述的抽象方法,它适用的场景是“mybatis”,“ jdbctemplate”,"本地事务"。下面我们就具体分析DataSourceTransactionManager的事务管理三大步骤详细处理流程。

一. DataSourceTransactionManager初始化事务

1. 获取事务名称 

    默认事务名称是被代理类的全限定名称+当前被拦截的方法名称,如: testmybatis.TxDao.findList。

2. 获取事务属性对象(TransactionDefinition)

    事务属性对象持有事务的相关配置,比如事务的隔离级别,传播行为,是否只读等。我们开启spring事务管理时,通常都会在配置文件里加入这样一段配置。

<tx:advice id="txAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<tx:method name="get*" read-only="true"/>
		<tx:method name="*"/>
	</tx:attributes>
</tx:advice>

     spring解析上述配置会创建两个事务属性对象。第一个事务属性对象适用于get前缀的方法对象,它是只读事务;第二个事务对象匹配非get前缀的其它方法,它使用默认事务配置,默认配置的话非只读,事务超时时间为-1,隔离级别使用数据库默认配置,传播行为是PROPAGATION_REQUIRED。

3. 获取事务管理器

    事务管理器跟事务属性对象一样,通常用户都已经配置好了,直接从spring的bean工厂获取,另外从配置也看出DataSourceTransactionManager持有dataSource。

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="jdbcDataSource" />
</bean>

4. 创建事务对象

   这个方法是AbstractPlatformTransactionManager定义的抽象方法,DataSourceTransactionManager实现了这个抽象方法,它创建的事务对象类型是DataSourceTransactionObject,事务管理器和事务对象之间是存在对应关系的。然后尝试从当前线程获取ConnectionHolder(连接持有器),赋值给事务对象。ConnectionHolder实现了ResourceHolder接口,它持有一个数据库连接,可以把凡是实现了ResourceHolder接口的对象看做是一种资源对象。默认情况下此时当前线程是不存在ConnectionHolder的,因此获取不到。插播一句,在spring事务管理过程中会用到一些线程安全对象,这些对象都交由TransactionSynchronizationManager管理,TransactionSynchronizationManager把这些对象都保存在ThreadLocal中。

5. 获取被挂起资源持有器

    被挂起资源持有器持有两类被挂起的资源,一类是资源对象,如上述的ConnectionHolder,一类是同步对象,即实现了TransactionSynchronization接口的对象。默认在这个时候事务同步还未被激活,因此返回null。

6. 创建事务状态对象

    被创建的事务状态对象类型是DefaultTransactionStatus,它持有上述创建的事务对象。事务状态对象主要用于获取当前事务对象的状态,比如事务是否被标记了回滚,是否是一个新事务等等。

7. 开始事务 

    7.1. 由于此时事务对象DataSourceTransactionObject持有的ConnectionHolder为null,因此首先需要创建ConnectionHolder对象,创建ConnectionHolder对象的前置条件是要先获取数据库连接对象,于是从dataSource获取连接对象,把连接设置成手动提交,完成ConnectionHolder对象的创建,然后赋值给事务对象。另外这个时候上述的事务属性对象派上用处了,根据事务属性对象配置连接的相关属性,如隔离级别、超时时间等。

    7.2. 把资源对象ConnectionHolder置入线程安全的map,key是dataSource对象,value是ConnectionHolder对象本身,当orm框架执行数据库操作需要连接对象时,获得就是这个ConnectionHolder持有的连接。

8. 预准备事务同步(主要是调用TransactionSynchronizationManager对象的方法,设置事务相关同步对象)

    8.1. 设置当前线程事务激活为true。

    8.2. 把事务隔离级别设置到当前线程。

    8.3. 把事务是否只读设置到当前线程。

    8.4. 把事务名称设置到当前线程。

    8.5. 实例化当前线程的同步对象,默认是一个空集。

9. 创建事务信息对象(TransactionInfo)

    事务信息对象持有“事务管理器”,“事务属性对象”,“事务状态对象”,可以把事务信息对象看做对以上几个对象的打包。然后把事务信息对象置入当前线程。

    

 

二. ORM框架执行数据库操作

      在这个过程中orm框架会调用spring的方法获取数据库连接对象,下面详细分析下这个过程。

1. 从dataSource获取数据库连接。

2. 根据连接创建ConnectionHolder,这是一个资源对象,设置ConnectionHolder是否跟事务同步的标志位为true,把ConnectionHolder置入当前线程,key是dataSource。

3. 根据ConnectionHolder创建ConnectionSynchronization,这是一个同步对象,把同步对象注册到当前线程。

4. 如果orm框架是mybatis,它会创建SqlSessionSynchronization(同步对象),它持有的资源对象是SqlSessionHolder。

关于同步对象,资源对象和事务之间的关系请看下图:

 

三. DataSourceTransactionManager回滚事务

1. 判断是否有必要对抛出的异常执行回滚操作,默认只要异常对象派生自RuntimeException或Error,都会执行回滚操作。这个用户是可以配置的,比如这样。

<tx:attributes>
	<tx:method name="*" rollback-for="com.cn.untils.exception.XyzException"/>
</tx:attributes>

2. 调用事务管理器的rollback(transactionStatus)方法,传入事务状态对象。

    2.1. 触发同步对象的beforeCompletion方法。

    2.2. 从事务对象获取连接持有器,然后再获取连接对象,调用连接的rollback()方法。

    2.3. 触发同步对象的afterCompletion方法。

 

四. DataSourceTransactionManager提交事务

1. 调用事务管理器的rollback(transactionStatus)方法,传入事务状态对象。

    1.1. 触发同步对象的beforeCommit方法。

    1.2. 触发同步对象的beforeCompletion方法。

    1.3. 从事务对象获取连接持有器,然后再获取连接对象,调用连接的commit()方法。

    1.4. 触发同步对象的afterCommit方法。

    1.5. 触发同步对象的afterCompletion方法。ro

转载于:https://my.oschina.net/u/157224/blog/1523837

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值