Spring支持以下7种事务传播行为。

传播行为

XML文件

propagation

含义

PROPAGATION_REQUIRED

REQUIRED

表示当前方法必须在一个具有事务的上下文中运行。

如果当前没有事务,就新建一个事务;如果已经存在一个事务,就加入到这个事务中。

(如果被调用端发生调用端需要回滚的异常,那么调用端和被调用端事务都将回滚;如果被调用端异常不是调用端需要回滚的,那么调用端终止执行,已执行操作正常提交)

PROPAGATION_SUPPORTS

SUPPORTS

表示当前方法不必需要具有一个事务上下文。

如果当前没有事务,就以非事务方式执行;但是如果有一个事务的话,它就加入到这个事务中运行。

PROPAGATION_MANDATORY

MANDATORY

表示当前方法必须在一个事务中运行。

如果当前没有事务,就抛出异常;如果有事务,就加入到这个事务中。

PROPAGATION_REQUIRES_NEW REQUIRES_NEW

表示当前方法必须运行在它自己的事务中,新建事务,如果当前存在事务,把当前事务挂起,直到新的事务提交或者回滚才恢复执行。

(如果被调用端抛出rollback异常,则被调用端回滚,如果同时是调用端的rollback异常,调用端同时回滚)

PROPAGATION_NOT_SUPPORTED

NOT_SUPPORTED

表示该方法不应该在一个事务中运行,应该以非事务方式执行,每句sql马上提交。

如果当前存在事务,就把当前事务挂起。

(如果被调用端抛出调用端rollback异常,则调用端回滚)

PROPAGATION_NEVER

NEVER

表示当前方法不应该在一个事务中运行,应该以非事务方式执行。

如果存在一个事务,则抛出异常

PROPAGATION_NESTED

NESTED

如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作;如果当前有一个事务,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。

(如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚;反之,内层事务并不影响外层事务,如果内层抛出异常不需rollback,则忽略,如果内层抛出异常需要rollback,则回滚到外层的savepoint)

spring中配置事务时,往往这样

<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="do*" read-only="false" rollback-for="java.lang.Exception"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice> <aop:config>
<aop:pointcut id="pc" expression="execution(* ffm.web.service.*.*(..))"/>
<aop:advisor pointcut-ref="pc" advice-ref="txAdvice"/>
</aop:config>

但是是怎么起作用的呢?

tx是TransactionNameSpace,对应的是handler是TxNamespaceHandler,<tx:advice />最终解析出一个以TransactionInerceptor为classname的beandefinition并且注册这个bean,拦截方法如下:

public Object invoke(final MethodInvocation invocation) throws Throwable {
Class targetClass = invocation.getThis() != null?AopUtils.getTargetClass(invocation.getThis()):null;
return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}

1. 调用父类 TransactionAspectSupport的invokeWithinTransaction方法:

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
//事务隔离级别、事务传播策略、只读、回滚等属性信息
final TransactionAttribute txAttr = this.getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = this.determineTransactionManager(txAttr);
final String joinpointIdentification = this.methodIdentification(method, targetClass);
if(txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) {
try {
Object ex1 = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
TransactionAspectSupport.TransactionInfo txInfo = TransactionAspectSupport.this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); TransactionAspectSupport.ThrowableHolder var4;
try {
Object ex = invocation.proceedWithInvocation();
return ex;
} catch (Throwable var8) {
if(txAttr.rollbackOn(var8)) {
if(var8 instanceof RuntimeException) {
throw (RuntimeException)var8;
} throw new TransactionAspectSupport.ThrowableHolderException(var8);
} var4 = new TransactionAspectSupport.ThrowableHolder(var8);
} finally {
TransactionAspectSupport.this.cleanupTransactionInfo(txInfo);
} return var4;
}
});
if(ex1 instanceof TransactionAspectSupport.ThrowableHolder) {
throw ((TransactionAspectSupport.ThrowableHolder)ex1).getThrowable();
} else {
return ex1;
}
} catch (TransactionAspectSupport.ThrowableHolderException var14) {
throw var14.getCause();
}
} else {
       // step 1.1
TransactionAspectSupport.TransactionInfo ex = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null; try {
retVal = invocation.proceedWithInvocation();
} catch (Throwable var15) {
this.completeTransactionAfterThrowing(ex, var15);
throw var15;
} finally {
          // step 1.2
this.cleanupTransactionInfo(ex);
} this.commitTransactionAfterReturning(ex);
return retVal;
}
}

1.1 关键方法createTransactionIfNecessary

protected TransactionAspectSupport.TransactionInfo createTransactionIfNecessary(PlatformTransactionManager tm, final TransactionAttribute txAttr, final String joinpointIdentification) {
if(txAttr != null && ((TransactionAttribute)txAttr).getName() == null) {
txAttr = new DelegatingTransactionAttribute((TransactionAttribute)txAttr) {
public String getName() {
return joinpointIdentification;
}
};
} TransactionStatus status = null;
if(txAttr != null) {
if(tm != null) {
          //step 1.1.1 调用org.springframework.jdbc.datasource.DataSourceTransactionManager
status = tm.getTransaction((TransactionDefinition)txAttr);
} else if(this.logger.isDebugEnabled()) {
this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured");
}
}
     //step 1.1.2绑定到当前线程
return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr, joinpointIdentification, status);
}

1.1.1 调用AbstractPlatformTransactionManager的getTransaction

public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
//step 1.1.1.1
Object transaction = this.doGetTransaction();
boolean debugEnabled = this.logger.isDebugEnabled();
if(definition == null) {
definition = new DefaultTransactionDefinition();
}

//step 1.1.1.2
if(this.isExistingTransaction(transaction)) {
return this.handleExistingTransaction((TransactionDefinition)definition, transaction, debugEnabled);
} else if(((TransactionDefinition)definition).getTimeout() < -1) {
throw new InvalidTimeoutException("Invalid transaction timeout", ((TransactionDefinition)definition).getTimeout());
} else if(((TransactionDefinition)definition).getPropagationBehavior() == 2) {
throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation \'mandatory\'");
} else if(((TransactionDefinition)definition).getPropagationBehavior() != 0 && ((TransactionDefinition)definition).getPropagationBehavior() != 3 && ((TransactionDefinition)definition).getPropagationBehavior() != 6) {
boolean newSynchronization1 = this.getTransactionSynchronization() == 0;
return this.prepareTransactionStatus((TransactionDefinition)definition, (Object)null, true, newSynchronization1, debugEnabled, (Object)null);
} else {
AbstractPlatformTransactionManager.SuspendedResourcesHolder newSynchronization = this.suspend((Object)null);
if(debugEnabled) {
this.logger.debug("Creating new transaction with name [" + ((TransactionDefinition)definition).getName() + "]: " + definition);
} try {
boolean err = this.getTransactionSynchronization() != 2;
DefaultTransactionStatus status = this.newTransactionStatus((TransactionDefinition)definition, transaction, true, err, debugEnabled, newSynchronization);
this.doBegin(transaction, (TransactionDefinition)definition);
this.prepareSynchronization(status, (TransactionDefinition)definition);
return status;
} catch (RuntimeException var7) {
this.resume((Object)null, newSynchronization);
throw var7;
} catch (Error var8) {
this.resume((Object)null, newSynchronization);
throw var8;
}
}
}

1.1.1.1调用 DataSourceTransactionManager doGetTransaction方法

protected Object doGetTransaction() {
DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject(null);
txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.dataSource);
txObject.setConnectionHolder(conHolder, false);
return txObject;
}

生成一个DataSourceTransactionObject 事物对象,设置它的ConnectionHolder为当前线程上绑定的key=this.dataSource的ConnectionHolder(当然有可能为空)

1.1.1.2开始处理这个新的 DataSourceTransactionObject 事物对象

DataSourceTransactionManager 的isExistingTransaction方法:

protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)transaction;
return txObject.getConnectionHolder() != null && txObject.getConnectionHolder().isTransactionActive();
}

如果返回true,

private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException {
if(definition.getPropagationBehavior() == 5) {
throw new IllegalTransactionStateException("Existing transaction found for transaction marked with propagation \'never\'");
} else {
AbstractPlatformTransactionManager.SuspendedResourcesHolder newSynchronization3;
boolean isoConstants2;
if(definition.getPropagationBehavior() == 4) {
if(debugEnabled) {
this.logger.debug("Suspending current transaction");
} newSynchronization3 = this.suspend(transaction);
isoConstants2 = this.getTransactionSynchronization() == 0;
return this.prepareTransactionStatus(definition, (Object)null, false, isoConstants2, debugEnabled, newSynchronization3);
} else if(definition.getPropagationBehavior() == 3) {
if(debugEnabled) {
this.logger.debug("Suspending current transaction, creating new transaction with name [" + definition.getName() + "]");
} newSynchronization3 = this.suspend(transaction); try {
isoConstants2 = this.getTransactionSynchronization() != 2;
DefaultTransactionStatus status = this.newTransactionStatus(definition, transaction, true, isoConstants2, debugEnabled, newSynchronization3);
this.doBegin(transaction, definition);
this.prepareSynchronization(status, definition);
return status;
} catch (RuntimeException var7) {
this.resumeAfterBeginException(transaction, newSynchronization3, var7);
throw var7;
} catch (Error var8) {
this.resumeAfterBeginException(transaction, newSynchronization3, var8);
throw var8;
}
} else {
boolean newSynchronization1;
if(definition.getPropagationBehavior() == 6) {
if(!this.isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException("Transaction manager does not allow nested transactions by default - specify \'nestedTransactionAllowed\' property with value \'true\'");
} else {
if(debugEnabled) {
this.logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
} if(this.useSavepointForNestedTransaction()) {
DefaultTransactionStatus newSynchronization2 = this.prepareTransactionStatus(definition, transaction, false, false, debugEnabled, (Object)null);
newSynchronization2.createAndHoldSavepoint();
return newSynchronization2;
} else {
newSynchronization1 = this.getTransactionSynchronization() != 2;
DefaultTransactionStatus isoConstants1 = this.newTransactionStatus(definition, transaction, true, newSynchronization1, debugEnabled, (Object)null);
this.doBegin(transaction, definition);
this.prepareSynchronization(isoConstants1, definition);
return isoConstants1;
}
}
} else {
if(debugEnabled) {
this.logger.debug("Participating in existing transaction");
} if(this.isValidateExistingTransaction()) {
if(definition.getIsolationLevel() != -1) {
Integer newSynchronization = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if(newSynchronization == null || newSynchronization.intValue() != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] specifies isolation level which is incompatible with existing transaction: " + (newSynchronization != null?isoConstants.toCode(newSynchronization, "ISOLATION_"):"(unknown)"));
}
} if(!definition.isReadOnly() && TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" + definition + "] is not marked as read-only but existing transaction is");
}
} newSynchronization1 = this.getTransactionSynchronization() != 2;
return this.prepareTransactionStatus(definition, transaction, false, newSynchronization1, debugEnabled, (Object)null);
}
}
}
}

初始下这个返回false,走下面的判断,根据传播机制

最后一个else有个关键方法doBegin,DataSourceTransactionManager 实现了这个抽象方法

protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)transaction;
Connection con = null; try {
if(txObject.getConnectionHolder() == null || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection ex = this.dataSource.getConnection();
if(this.logger.isDebugEnabled()) {
this.logger.debug("Acquired Connection [" + ex + "] for JDBC transaction");
} txObject.setConnectionHolder(new ConnectionHolder(ex), true);
} txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
Integer ex1 = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(ex1);
if(con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if(this.logger.isDebugEnabled()) {
this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
} con.setAutoCommit(false);
} txObject.getConnectionHolder().setTransactionActive(true);
int timeout = this.determineTimeout(definition);
if(timeout != -1) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
} if(txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(this.getDataSource(), txObject.getConnectionHolder());
} } catch (Throwable var7) {
if(txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, this.dataSource);
txObject.setConnectionHolder((ConnectionHolder)null, false);
} throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", var7);
}
}

可以看出,这里给DataSourceTransactionObject 事物对象设置它的ConnectionHolder,真正打开连接激活事务,并把这个ConnectionHolder绑定在当前线程上(key=this.dataSource)

1.1.2 生成一个TransactionInfo,设置TransactionStatus为上一步1.1.1得到的TransactionStatus,并把自己绑定 到当前线程

protected TransactionAspectSupport.TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm, TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {
TransactionAspectSupport.TransactionInfo txInfo = new TransactionAspectSupport.TransactionInfo(tm, txAttr, joinpointIdentification);
if(txAttr != null) {
if(this.logger.isTraceEnabled()) {
this.logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
} txInfo.newTransactionStatus(status);
} else if(this.logger.isTraceEnabled()) {
this.logger.trace("Don\'t need to create transaction for [" + joinpointIdentification + "]: This method isn\'t transactional.");
} txInfo.bindToThread();
return txInfo;
}
TransactionInfo的bindToThread方法:
private void bindToThread() {
this.oldTransactionInfo = (TransactionAspectSupport.TransactionInfo)TransactionAspectSupport.transactionInfoHolder.get();
TransactionAspectSupport.transactionInfoHolder.set(this);
}

1.2 重置当前线程的TransactionInfo为oldTransactionInfo

private void restoreThreadLocalStatus() {
TransactionAspectSupport.transactionInfoHolder.set(this.oldTransactionInfo);
}

以常用的propagation="SUPPORTS" / "REQUIRED"为例,分析跟踪事务的过程

  • SUPPORTS->REQUIRED,`一路到1.1.1.2,isExistingTransaction返回false,进入
if(((TransactionDefinition)definition).getPropagationBehavior() != 0 && ((TransactionDefinition)definition).getPropagationBehavior() != 3 && ((TransactionDefinition)definition).getPropagationBehavior() != 6) {
boolean newSynchronization1 = this.getTransactionSynchronization() == 0;
return this.prepareTransactionStatus((TransactionDefinition)definition, (Object)null, true, newSynchronization1, debugEnabled, (Object)null);

以非事务方式运行,接着调用REQUIRED的方法,直到1.1.1.2,isExistingTransaction返回false,进入最后一个else,打开新事务

  • REQUIRED->SUPPORTS,到1.1.1.2时,isExistingTransaction返回false,进入最后一个else,打开新事务。接着调用SUPPORTS的方法,到达1.1.1.2时发现有事务,进入handleExistingTransaction处理,最终加入已有事务

参考文章:

1. 揭开Spring事务处理

2. Spring中的事务控制学习中(转)

3. Spring 事务管理高级应用难点剖析--转

4. spring源码分析之——spring 事务管理实现方式

5. Spring @Transactional 如何开启事务

6. 详解spring事务属性

7. Spring事务处理的实现

8. spring事务传播机制实例讲解

spring--事务原理的更多相关文章

  1. Spring事务原理分析-部分二

    Spring事务原理分析-部分二 说明:这是我在蚂蚁课堂学习了余老师Spring手写框架的课程的一些笔记,部分代码代码会用到余老师的课件代码.这不是广告,是我听了之后觉得很好. 课堂链接:Spring ...

  2. Spring事务原理分析-部分一

    Spring事务原理分析-部分一 什么事务 事务:逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败. 事务基本特性 ⑴ 原子性(Atomicity) 原子性是指事务包含的所有操作要 ...

  3. 深入理解 Spring 事务原理

    本文由码农网 – 吴极心原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 一.事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供 ...

  4. 深入理解 Spring 事务原理【转】

    本文转自码农网 – 吴极心原创  连接地址:http://www.codeceo.com/article/spring-transactions.html 一.事务的基本原理 Spring事务的本质其 ...

  5. 事务之四:Spring事务--原理

    一.Spring事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的.对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行: ...

  6. 理解 Spring 事务原理

    转载:https://www.jianshu.com/p/4312162b1458 一.事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事 ...

  7. Spring事务原理一探

    概括来讲,事务是一个由有限操作集合组成的逻辑单元.事务操作包含两个目的,数据 一致以及操作隔离.数据一致是指事务提交时保证事务内的所有操作都成功完成,并且 更改永久生效:事务回滚时,保证能够恢复到事务 ...

  8. 一文带你深入浅出Spring 事务原理

    Spring事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的.对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行: 获 ...

  9. Spring事务原理分析--手写Spring事务

    一.基本概念和原理 1.Spring事务 基于AOP环绕通知和异常通知的 2.Spring事务分为编程式事务.声明事务.编程事务包括注解方式和扫包方式(xml) Spring事务底层使用编程事务(自己 ...

  10. 【Spring】看了这篇Spring事务原理,我才知道我对Spring事务的误解有多深!

    写在前面 有很多小伙伴们留言说,冰河,你能不能写一篇关于Spring事务的文章呢?我:可以啊,安排上了!那还等什么呢?走起啊!! 事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有 ...

随机推荐

  1. Fragment实现底部选项卡切换效果

    现在很多APP的样式都是底部选项卡做为首页的,实现这样的效果,我们一般有这样几种方式,第一,最屌丝的做法,我直接自定义选项卡视图,通过监听选项卡视图,逻辑控制内容页的切换,这样做的想法一般是反正这几个 ...

  2. 转载:js和as间的交互

    转载一: 提及AS3与外部脚本的交互,笔者认为可以总结成两种.一是AS3调用外部函数,二是外部脚本调用AS3函数.无外乎就 这两种.在调用函数的同时,我们还可以向函数传递一些参数.这就达到了传递数据的 ...

  3. 支付宝修改回调地址后 issign=false

    原因: verifyReturn 拼接url的时候,php自动添加了url参数,而url是本不需要的,所以导致md5对比出错. 修改  alipay_notify.class.php  77行的函数 ...

  4. HDU 5601 N*M bulbs 找规律

    N*M bulbs 题目连接: http://codeforces.com/contest/510/problem/C Description NM个灯泡排成一片,也就是排成一个NM的矩形,有些开着, ...

  5. hdu 5592 ZYB's Game 树状数组

    ZYB's Game Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=55 ...

  6. 如何从iTunes Connect中提款呢?

    最近在AppStore有点小小小收入,但如何从iTunes Connect中提款呢? (Payments and Financial Reports) 网上查了下,发现有种说法:“只要账号余额达到15 ...

  7. or1200下raw-os学习(任务篇)

    这次就来说说基于上一节介绍的系统框图去建立我们所需要的任务,顺便学习Raw-OS提供的API,根据上节的分析,对于Slave Board有如下设计: Slave Board有三个任务,分别负责测试阻抗 ...

  8. 一份Java学习路线图

    Java学习路线图 本文会持续更新,敬请关注.下划线的文字会在这个博客继续更新. 回顾自己的Java学习经历,从学校的课堂到现在每天的项目开发,一份路线路线图浮出来. 其中有未做好的地方,也有自我感觉 ...

  9. Grunt打造前端自动化工作流

    HTML去掉注析.换行符 - HtmlMin CSS文件压缩合并 – CssMinify JS代码风格检查 – JsHint JS代码压缩 – Uglyfy image压缩 - imagemin ht ...

  10. mysql开启慢查询方法(转)

    1,配置开启 Linux: 在mysql配置文件my.cnf中增加 log-slow-queries=/var/lib/mysql/slowquery.log (指定日志文件存放位置,可以为空,系统会 ...