spring事务深入剖析 - 事务框架
本文以申明式事务为例,开始下探,分析spring事务的源码结构,再以mybatis为例,分析spring事务是如何作用于ORM的。
首先看看spring的配置文件,简而言之,TransactionAttributeSourceAdvisor采用AOP方式,将事务transactionInterceptor织入注解的特定的方法上
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"> <property name="transactionInterceptor"><ref bean="transactionInterceptor"/></property> </bean> <bean id="transactionInterceptor" class="com.CustomerTransactionInterceptor"> <constructor-arg name="ptm" ref="shardingTransactionManager"></constructor-arg> <constructor-arg name="tas" ref="transactionAttributeSource"></constructor-arg> </bean> <bean id="customerSpringTransactionAnnotationParser" class="com.CustomerSpringTransactionAnnotationParser"> <constructor-arg name="transactionManagerSpringBeanId"> <value>shardingTransactionManager</value> </constructor-arg> </bean> <bean id="transactionAttributeSource" class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"> <constructor-arg name="annotationParser" ref="customerSpringTransactionAnnotationParser"></constructor-arg> </bean>
那实际上,transactionInterceptor是实际调用shardingTransactionManager入口,它的父类TransactionAspectSupport封装了操作事务的具体代码
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
最终,在这个类里,我们找到了核心的事务操作代码,很清晰的,几步
1. 从属性中获取事务属性配置,从BeanFactory中去除TransactionManager
2. 开启事务,createTransactionIfNecessary
3. 执行业务方法
4. 遇错回滚,completeTransactionAfterThrowing方法判断,该Exception类型是否回滚,不回滚执行提交
5. 清理事务信息,cleanupTransactionInfo将当前TransactionInfo设置为old
6. 提交,commitTransactionAfterReturning执行提交
protected Object invokeWithinTransaction(Method method, Class targetClass, final InvocationCallback invocation)
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); final PlatformTransactionManager tm = determineTransactionManager(txAttr); final String joinpointIdentification = methodIdentification(method, targetClass); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } commitTransactionAfterReturning(txInfo); return retVal; }
事务的外围展现就是这么简单,内部的处理的复杂性主要有以下几点
1. 由于拦截事务是嵌套的,所以产生了以上6步执行的嵌套问题,这就产生了事务的传播特性
2. 底层数据库的不同,数据库驱动程序不同,产生了事务的兼容性问题
3. ORM框架百花齐放,如何能和spring事务无缝整合,也是一个棘手的问题
接下来我们先以JDBC事务为例进行说明
先看xml文件的配置,可以知道JDBC的事务管理器为DataSourceTransactionManager
<!-- Sharding start --> <bean id="shardingTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="shardingDataSource" /> </bean>首先,我们先看Spring是如何兼容JDBC驱动的事务的
DataSourceTransactionManager和JDBC事务的具体封装在spring-jdbc-xxx.jar中,DataSourceTransactionManager的父类AbstractPlatformTransactionManager在spring-tx-xxx.jar中,其中后者为spring对事务的抽象层,前者是JDBC事务的具体实现。代码中设计底层的交给DataSourceTransactionManager子类实现,AbstractPlatformTransactionManager封装上层接口,事务的调用都走上层接口。
接下来我们从上面的六步着手,逐层下探
1. 事务的创建,方法的调用流程如下
TransactionAspectSupport.createTransactionIfNecessary->AbstractPlatformTransactionManager.getTransaction->DataSourceTransactionManager.*
AbstractPlatformTransactionManager.getTransaction方法
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { //调用DataSourceTransactionManager获得transaction句柄对象 Object transaction = doGetTransaction(); //如果事务存在,根据事务的传播类型,进行对应的处理 if (isExistingTransaction(transaction)) { return handleExistingTransaction(definition, transaction, debugEnabled); } //以前不存在事务,doBegin启动事务 else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { doBegin(transaction, definition);
private TransactionStatus handleExistingTransaction( TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException { if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) { //该方法绝对不能在事务范围内执行。如果在就抛例外。只有该方法没有关联到任何事务,才正常执行。 } if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) { //声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。 suspend(transaction); } if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) { //不管是否存在事务,该方法总汇为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。 suspend(transaction); } if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { //如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。 }
总结一下,AbstractPlatformTransactionManager.getTransaction共涉及DataSourceTransactionManager的四个方法,具体方法的分析移步到http://blue2048.iteye.com/admin/blogs/2176676
1. doGetTransaction
2. isExistingTransaction
3. doBegin
4. doSuspend
2. 事务的回滚,方法的调用流程如下
TransactionAspectSupport.completeTransactionAfterThrowing->AbstractPlatformTransactionManager.processRollback->DataSourceTransactionManager.doRollback
protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) { if (txInfo.transactionAttribute.rollbackOn(ex)) { //如果对ex敏感,回滚事务 txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); }else { //不对ex敏感,提交事务 txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } }
TransactionAspectSupport.commitTransactionAfterReturning->AbstractPlatformTransactionManager.processCommit->DataSourceTransactionManager.*
//事务如果是最外层事务,则进行真是提交,否则执行resume
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
if (status.isNewTransaction()) {
doCommit(status);
}
cleanupAfterCompletion(status);
}
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
doCleanupAfterCompletion(status.getTransaction());
resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
}
protected final void resume(Object transaction, SuspendedResourcesHolder resourcesHolder)
throws TransactionException {
doResume(transaction, suspendedResources);
}
总结一下,AbstractPlatformTransactionManager.processCommit共涉及DataSourceTransactionManager的四个方法,具体方法的分析移步到http://blue2048.iteye.com/admin/blogs/2176676
1. doCommit
2. doCleanupAfterCompletion
3. doResume
上一篇: 游戏推荐:Nuclear Throne
下一篇: 医生果然是医生
推荐阅读
-
spring实现jdbctemplate添加事务支持示例
-
Spring的事务机制实例代码
-
CodeIgniter框架数据库事务处理的设计缺陷和解决方案
-
深入剖析 RabbitMQ —— Spring 框架下实现 AMQP 高级消息队列协议
-
Spring事务处理流程和原理详解
-
使用Python的Django框架实现事务交易管理的教程
-
Mybaits 源码解析 (十二)----- Mybatis的事务如何被Spring管理?Mybatis和Spring事务中用的Connection是同一个吗?
-
Spring 事务隔离与事务传播的详解与对比
-
深入剖析Python的爬虫框架Scrapy的结构与运作流程
-
spring事务的@Transactional使用事务不生效问题