Spring001--事务的传播机制
Spring事务的传播机制
本文来自于博客:https://blog.csdn.net/yuanlaishini2010/article/details/45792069
一。事务的嵌套概念
事务的嵌套就是两个事务方法之间相互调用。
spring事务开启 ,或者是基于接口的或者是基于类的代理被创建(注意一定要是代理,不能手动new 一个对象,并且此类(有无接口都行)一定要被代理——spring中的bean只要纳入了IOC管理都是被代理的)。所以在同一个类中一个方法调用另一个方法(有事务的方法),事务是不会起作用的。
让checked例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class) 让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class) 不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED)
上面三种方式也可在xml配置
二。spring事务传播属性
在 spring的 TransactionDefinition接口中一共定义了6种事务传播属性:
PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。 PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。
它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager)
举例浅析Spring嵌套事务
ServiceA#methodA(我们称之为外部事务),ServiceB#methodB(我们称之为内部事务)
ServiceA {
void methodA() {
ServiceB.methodB();
}
} ServiceB {
void methodB() {
}
}
【1】。PROPAGATION_REQUIRED: (需要事务)
支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
(1)。ServiceA.methodA有事务
ServiceA.methodA启动事务,调用ServiceB.methodB,ServiceB.methodB发现在事务A中,则不再启动新事务。此时仅有外部事务,无论A还是B发生异常,methodA & methodB均会一起回滚。
(2)。ServiceA.methodA没有事务
ServiceA.methodA没有事务,ServiceB.methodB就会为自己分配一个事务。这样,在ServiceA.methodA中是没有事务控制的。只是在ServiceB.methodB内的任何地方出现异常,ServiceB.methodB将会被回滚,不会引起ServiceA.methodA的回滚。
【2】。PROPAGATION_SUPPORTS:(支持事务)
如果当前在事务中,即以事务的形式运行,如果当前不在一个事务中,那么就以非事务的形式运行
即:methodA有事务,methodB在methodA事务中,则以事务形式运行。
methodA没有事务,methodB在methodA无事务中,则以非事务形式运行。
【3】。PROPAGATION_MANDATORY:
必须在一个事务中运行。也就是说,他只能被一个父事务调用。否则,他就要抛出异常.
【4】。PROPAGATION_REQUIRES_NEW:
启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内部事务结束时, 外部事务将继续执行.
例如:
我们设计ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW,
那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后,他才继续执行。 他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为ServiceB.methodB是新起一个事务,那么就是存在两个不同的事务。 、如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。 、如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA的try..catch捕获并处理,ServiceA.methodA事务仍然可能提交; 如果他抛出的异常未被ServiceA.methodA捕获处理,ServiceA.methodA事务将回滚。 使用场景:
不管业务逻辑的service是否有异常,Log Service都应该能够记录成功,所以Log Service的传播属性可以配为此属性。最下面将会贴出配置代码。
【5】。PROPAGATION_NOT_SUPPORTED:(不支持事务)
如:ServiceA.methodA的事务级别是PROPAGATION_REQUIRED ,而ServiceB.methodB的事务级别是PROPAGATION_NOT_SUPPORTED ,
那么当执行到ServiceB.methodB时,ServiceA.methodA的事务挂起,而methodB以非事务的状态运行完,再继续ServiceA.methodA的事务。
【6】。PROPAGATION_NEVER:(不能在事务中运行)
假设ServiceA.methodA的事务级别是PROPAGATION_REQUIRED, 而ServiceB.methodB的事务级别是PROPAGATION_NEVER ,
那么ServiceB.methodB就要抛出异常了。
【7】。PROPAGATION_NESTED(开始一个 "嵌套的" 事务)
它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.
比如我们设计ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_NESTED, 那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的子事务并设置savepoint, 等待ServiceB.methodB的事务完成以后,他才继续执行。。因为ServiceB.methodB是外部事务的子事务,那么
、如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB也将回滚。
、如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA的try..catch捕获并处理,ServiceA.methodA事务仍然可能提交; 如果他抛出的异常未被ServiceA.methodA捕获处理,ServiceA.methodA事务将回滚。
. 我们要设置 transactionManager 的 nestedTransactionAllowed 属性为 true, 注意, 此属性默认为 false!!!
. java.sql.Savepoint 必须存在, 即 jdk 版本要 1.4+
. Connection.getMetaData().supportsSavepoints() 必须为 true, 即 jdbc drive 必须支持 JDBC 3.0
确保以上条件都满足后, 你就可以尝试使用 PROPAGATION_NESTED 了.
三。Log Service配置事务传播
不管业务逻辑的service是否有异常,Log Service都应该能够记录成功,通常有异常的调用更是用户关心的。
Log Service如果沿用业务逻辑Service的事务的话在抛出异常时将没有办法记录日志(事实上是回滚了)。
所以希望Log Service能够有独立的事务。日志和普通的服务应该具有不同的策略。
Spring 配置文件transaction.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<!-- configure transaction --> <tx:advice id="defaultTxAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="query*" read-only="true" />
<tx:method name="find*" read-only="true" />
<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
</tx:attributes>
</tx:advice> <tx:advice id="logTxAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="query*" read-only="true" />
<tx:method name="find*" read-only="true" />
<tx:method name="*" propagation="REQUIRES_NEW"
rollback-for="java.lang.Exception" />
</tx:attributes>
</tx:advice> <aop:config>
<aop:pointcut id="defaultOperation"
expression="@within(com.homent.util.DefaultTransaction)" />
<aop:pointcut id="logServiceOperation"
expression="execution(* com.homent.service.LogService.*(..))" /> <aop:advisor advice-ref="defaultTxAdvice" pointcut-ref="defaultOperation" />
<aop:advisor advice-ref="logTxAdvice" pointcut-ref="logServiceOperation" />
</aop:config>
</beans>
如上面的Spring配置文件所示,日志服务的事务策略配置为propagation="REQUIRES_NEW",
告诉Spring不管上下文是否有事务,Log Service被调用时都要求一个完全新的只属于Log Service自己的事务。
通过该事务策略,Log Service可以独立的记录日志信息,不再受到业务逻辑事务的干扰。
Spring001--事务的传播机制的更多相关文章
- 数据库的特性与隔离级别和spring事务的传播机制和隔离级别
首先数据库的特性就是 ACID: Atomicity 原子性:所有事务是一个整体,要么全部成功,要么失败 Consistency 一致性:在事务开始和结束前,要保持一致性状态 Isolation 隔离 ...
- spring事务的传播机制新解
以下是事物的传播机制: @Transactional(propagation=Propagation.REQUIRED)如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)@Transacti ...
- Spring事务之传播机制
Spring事务传播机制:Spring在TransactionDefinition接口中规定了种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套时事务如何进行传播.即协调已经有事务标识的方法之 ...
- Solon详解(四)- Solon的事务传播机制
在前面的篇章里我们已经见识了 Solon 对事务的控制,及其优雅曼妙的形态.该篇将对事务的传播机制做讲解.出于对用户的学习成本考虑,Solon 借签了Spring 的事务传播策略:并友好的支持多数据源 ...
- 18个示例详解 Spring 事务传播机制(附测试源码)
什么是事务传播机制 事务的传播机制,顾名思义就是多个事务方法之间调用,事务如何在这些方法之间传播. 举个例子,方法 A 是一个事务的方法,方法 A 执行的时候调用了方法 B,此时方法 B 有无事务以及 ...
- spring事务传播机制实例讲解
http://kingj.iteye.com/blog/1680350 spring事务传播机制实例讲解 博客分类: spring java历险 天温习spring的事务处理机制,总结 ...
- Spring事务传播机制
Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播,即协调已经有事务标识的方法之间的发生调用时的事务 ...
- Spring事务传播机制和数据库隔离级别
Spring事务传播机制和数据库隔离级别 转载 2010年06月26日 10:52:00 标签: spring / 数据库 / exception / token / transactions / s ...
- spring 事务传播机制
spring 事务 传播机制 描述的 事务方法直接相互调用,父子事物开启,挂起,回滚 等的处理方式. 绿色的 那几个 我认为比较重要. 1 , @Transactional(propagation=P ...
随机推荐
- bzoj4011 [HNOI2015]落忆枫音 拓扑排序+DP
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4011 题解 首先考虑如果没有那么一条被新加进来的奇怪的边的做法. 我们只需要给每一个点挑一个父 ...
- java IO操作分类
- 【BZOJ1488】[HNOI2009]图的同构计数
题目链接 题意 求 n 个点的同构意义下不同的图的数量.\((n\leq 60)\) Sol \(Polya\) 定理的练手题. 我们这里先把边的存在与否变成对边进行黑白染色,白色代表不存在,这样就变 ...
- H5 图片上传
1.h5 图片异步上传 (1) 异步上传input触发onchange事件的时候,就把图片上传至服务器.后台可能会返回图片的链接等信息,前台可以把图片信息展示给用户看. (2) 另一种情况可能需要前台 ...
- axios中put和patch的区别(都是update , put是需要提交整个对象资源,patch是可以修改局部)
patch方法用来更新局部资源,这句话我们该如何理解? 假设我们有一个UserInfo,里面有userId, userName, userGender等10个字段.可你的编辑功能因为需求,在某个特别的 ...
- 使用IDEA连接mysql数据库
1.IDEA配置数据库连接 2.添加数据库: 3.填写数据库信息: database输入框里面填写要连接的数据库名称 然后点击test connection,会弹出一个框,提示下载驱动,点击进行下载即 ...
- linux运维、架构之路-Kickstart无人值守
一.PXE介绍 PXE全名Pre-boot Execution Environment,预启动执行环境:通过网络接口启动计算机,不依赖本地存储设备或本地已安装的操作系统:Client ...
- cookie、session和会话保持
1.会话 在程序中,会话跟踪是很重要的事情.理论上,一个已登录用户,在这次登录后进行的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆.例如,用户 A 在 ...
- 有关于TreeSet的自我理解
TreeSet是依靠TreeMap来实现的. TreeSet是一个有序集合,TreeSet中的元素将按照升序排列,缺省是按照自然排序进行排列,意味着TreeSet中的元素要实现Comparable接口 ...
- CF704D Captain America
http://codeforces.com/problemset/problem/704/D 题解 对于两种颜色的染色,我们可以把它看做选择问题. 比如说红色的代价小,所以我们尽可能多的染红色. 然后 ...