spring交易声明的几个传播特性

近期遇到了一个spring事务导致的问题,所以写了几个小程序了解了一下事务的传播特性,以下分别举样例分别看看事务的传播特性。

事务的几种传播特性

1. PROPAGATION_REQUIRED: 假设存在一个事务,则支持当前事务。

假设没有事务则开启

Java代码  

  1. /**
  2. * TransactionTestService     test1和test2配有事务(PROPAGATION_REQUIRED) */
  3. public interface TransactionTestService {
  4. //事务属性 PROPAGATION_REQUIRED
  5. public void test1() throws Exception{
  6. avInfoTaskTunnel.insertAvInfoTask();
  7. test2();
  8. }
  9. //事务属性 PROPAGATION_REQUIRED
  10. public void test2() throws Exception{
  11. avRequestTunnel.insertAvRequest();
  12. throw new Exception();
  13. }
  14. }
  15. /**
  16. * main
  17. */
  18. public class TransactionTestMain {
  19. public static void main(String[] args) throws Exception{
  20. TransactionTestService transactionTestService = (TransactionTestService)context.getBean("transactionTestService");
  21. try {
  22. transactionTestService.test1();
  23. } catch (Exception e) {
  24. }
  25. }
  26. }

上述代码中test1()和test2()都配有PROPAGATION_REQUIRED事务属性,test1()内部调用test2(),这样test1()和test2()方法将都处于同一事务之中,当在test2()中抛出异常。会导致test1()和test2()方法中的事务都回滚。

可是,假设test1()方法对调用test2()时捕获异常,结果会是如何的呢? test1应该能正常写入没问题,那么test2呢?

Java代码  

  1. //test1()中捕获test2()抛出的异常
  2. public void test1() throws Exception{
  3. avInfoTaskTunnel.insertAvInfoTask();
  4. try {
  5. test2();
  6. }catch (Exception e) {
  7. }
  8. }

最后的结果test2()也将会正常的写入。

事实上,上面情况中假设仅仅是test1()配有PROPAGATION_REQUIRED事务属性。test2()不配置不论什么事务属性。发生的结果也是一致的。上面的情形相当于:

Java代码  

  1. public static void main(String[] args) throws Exception{
  2. Connection con = null;
  3. try {
  4. con=getConnection();
  5. con.setAutoCommit(false);
  6. transactionTestService.test1(); //test1()和test2()处于同一事务之中
  7. con.commit();
  8. } catch (Exception e) {
  9. con.rollback();
  10. } finally {
  11. closeCon();
  12. }
  13. }

上述test1()和test2()是同一个类的两个方法,那么要是它们处于不同类呢?

Java代码  

  1. //main函数不变,test1()中调用test2()地方换成调用还有一个类中配有PROPAGATION_REQUIRED事务属性的方法
  2. //不正确otherService.test2()捕获异常的情形就不是必需说了。必然都回滚。
  3. public void test1() throws Exception{
  4. avInfoTaskTunnel.insertAvInfoTask();
  5. try {
  6. otherService.test2();  //PROPAGATION_REQUIRED事务属性
  7. } catch (Exception e) {
  8. }
  9. }
  10. //otherService.test2()
  11. public void test2() throws Exception{
  12. avRequestTunnel.insertAvRequest();
  13. throw new Exception();
  14. }

上述相同捕获了异常,可是结果会如何呢? 结果有点出乎意料。与之前test1(),test2()处于同一类的情形不同,这个时候。两个方法都将回滚。而且在调用test1()的地方会抛出以下异常。

这是因为子事务在回滚的时候已经将主事务标记成了rollback-only,这样导致主事务在提交的时候就会抛出以下这个异常。

另外:假设otherService.test2()没有配置不论什么事务属性,那么test2()抛出异常的时候,将导致test1()和test2()都回滚。

Java代码  

  1. org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

上述情况网上查询到一种解决方案是在transactionManager中将globalRollbackOnParticipationFailure 设置为

q=false&ie=utf-8&src=se_lighten" style="color:rgb(16,138,198)">false(默认是true)。可是这样又带来还有一个问题,子事务也给一并提交了(这个时候子事务产生异常,不想提交),详细的解决方案还没找到。可是我认为不应该将这两个配置在同一事务中。

Xml代码  

  1. <bean id="transactionManager"
  2. class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  3. <property name="dataSource">
  4. <ref local="dataSource" />
  5. </property>
  6. <property name="globalRollbackOnParticipationFailure" value="false" />
  7. </bean>
2. PROPAGATION_SUPPORTS: 假设存在一个事务,支持当前事务。假设没有事务,则非事务的运行

Java代码  

  1. //TransactionTestService     test1()配有事务(PROPAGATION_SUPPORTS)
  2. public void test1() throws Exception{
  3. avInfoTaskTunnel.insertAvInfoTask();
  4. throw new Exception();
  5. }
  6. /**
  7. * main
  8. */
  9. public class TransactionTestMain {
  10. public static void main(String[] args) throws Exception{
  11. TransactionTestService transactionTestService = (TransactionTestService)context.getBean("transactionTestService");
  12. try {
  13. transactionTestService.test1();
  14. } catch (Exception e) {
  15. }
  16. }
  17. }

TransactionTestService的test1()配有PROPAGATION_SUPPORTS事务属性,我们知道这样的情形下假设配的是PROPAGATION_REQUIRED事务属性。那么test1()将新建事务执行。可是PROPAGATION_SUPPORTS属性不会新建,这样的情形下,test1()方法将正常提交。那假设是外层事务配有事务呢?例如以下所看到的,此种情形test2()将处于事务之中了。

Java代码  

  1. //PROPAGATION_REQUIRED事务属性
  2. public void test1() throws Exception{
  3. avInfoTaskTunnel.insertAvInfoTask();
  4. test2();
  5. }
  6. //PROPAGATION_SUPPORTS事务属性
  7. public void test2() throws Exception{
  8. avRequestTunnel.insertAvRequest();
  9. throw new Exception();
  10. }
3. PROPAGATION_MANDATORY: 假设已经存在一个事务,支持当前事务。假设没有一个活动的事务。则抛出异常。

Java代码  

  1. //情形1:PROPAGATION_REQUIRED事务属性  情形2:不配不论什么事务属性
  2. public void test1() throws Exception{
  3. avInfoTaskTunnel.insertAvInfoTask();
  4. otherService.test2();
  5. }
  6. //otherService的test2()配置PROPAGATION_MANDATORY事务属性
  7. public void test2() throws Exception {
  8. avRequestTunnel.insertAvRequest();
  9. throw new Exception();
  10. }
  11. //test1()处于情形2时抛出异常,test2()不可以提交,可是test1()却是可以成功提交的
  12. org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation ‘mandatory‘

上述情况,当test1()处于情形1时,会是的test1()和test2()都处于事务其中;test1()处于情形2时,就会抛异常,可是这个时候test2()不可以提交,可是test1()却是可以成功提交的。此外,另一点,注意上述test2()是处于另一个类中的,假设是处于同一个类。那么PROPAGATION_MANDATORY不会由于外层是否有事务而抛异常。

4. PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务。假设一个事务已经存在,则将这个存在的事务挂起。

Java代码  

  1. //情形1:PROPAGATION_REQUIRED事务属性  情形2:不配不论什么事务属性
  2. public void test1() throws Exception{
  3. avInfoTaskTunnel.insertAvInfoTask();
  4. otherService.test2();
  5. }
  6. //otherService的test2()配置PROPAGATION_REQUIRES_NEW事务属性
  7. public void test2() throws Exception {
  8. avRequestTunnel.insertAvRequest();
  9. throw new Exception();
  10. }

上述情况,test1()处于情形2时test2()新建事务。这点没有问题。那假设test1()处于情形1呢?也就是说test1()已经有事务了。结果是test2()处于新的事务中,怎么确定是处于新的事务中呢?看以下代码:

Java代码  

  1. //test1配置PROPAGATION_REQUIRED事务属性
  2. public void test1() throws Exception{
  3. avInfoTaskTunnel.insertAvInfoTask();
  4. otherService.test2();  //PROPAGATION_REQUIRES_NEW事务属性
  5. }
  6. //otherService.test2()
  7. public void test2() throws Exception{
  8. avRequestTunnel.insertAvRequest();
  9. throw new Exception();
  10. }

假设是在同一事务中。那么情形将同于讲述PROPAGATION_REQUIRED属性时的情形。test1()和test2()都将回滚,而且抛出异常事务被打上rollback-only标记的异常。可是这里,结果就是test2()回滚,test1正常提交,所以otherService.test2()处于新的事务中。注意:上述情况test2()也是还有一个类的方法,假设属于同一类,也就是test1()和test2()处于同一个类。test1()中调用test2(),那么配置的PROPAGATION_REQUIRES_NEW将无效(跟test2()什么事务属性都没配置一样)。

可是假设是main函数中直接调用test2(),那么还是会起一个新的事务。

第二种证明test1()和test2()处于不同事务的方式是,在test2()不抛出异常,然后再test1()调用了test2()之后,抛出异常,最后结果是()回滚。test2()正常提交。

5. PROPAGATION_NOT_SUPPORTED: 总是非事务地运行,并挂起不论什么存在的事务。

Java代码  

  1. //test1配置PROPAGATION_REQUIRED事务属性
  2. public void test1() throws Exception{
  3. avInfoTaskTunnel.insertAvInfoTask();
  4. otherService.test2();  //PROPAGATION_NOT_SUPPORTED事务属性
  5. }
  6. //otherService.test2()
  7. public void test2() throws Exception{
  8. avRequestTunnel.insertAvRequest();
  9. throw new Exception();
  10. }

假设otherService.test2() 没有配置事务属性,那么test2()抛出异常时,test1()和test2()都回滚。可是如今test2()配置了PROPAGATION_NOT_SUPPORTED事务属性,那么test2()将以非事务执行,而test1()继续执行在事务中。也就是说,此时,test1()回滚,test2()正常提交。

注意:假设test1()和test2()在同一类中。那么test2()的PROPAGATION_NOT_SUPPORTED失效。

6. PROPAGATION_NEVER: 总是非事务地运行。假设存在一个活动事务,则抛出异常

Java代码  

  1. //test1配置PROPAGATION_REQUIRED事务属性
  2. public void test1() throws Exception{
  3. avInfoTaskTunnel.insertAvInfoTask();
  4. otherService.test2();  //PROPAGATION_NEVER事务属性
  5. }
  6. //otherService.test2()
  7. public void test2() throws Exception{
  8. avRequestTunnel.insertAvRequest();
  9. throw new Exception();
  10. }
  11. //test1()配置PROPAGATION_REQUIRED事务属性, otherService.test2()配置PROPAGATION_NEVER事务属性,将抛以下异常:
  12. org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation ‘never‘

当然上述情况。假设是test1()和test2()在同一类中。那么PROPAGATION_NEVER也将失效。

7. PROPAGATION_NESTED:假设一个活动的事务存在,则执行在一个嵌套的事务中. 假设没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行

最easy弄混淆的事实上是 PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED。

PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被全然 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务開始运行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续运行。还有一方面, PROPAGATION_NESTED 開始一个 "嵌套的"
事务, 它是已经存在事务的一个真正的子事务. 嵌套事务開始运行时, 它将取得一个 savepoint. 假设这个嵌套事务失败, 我们将回滚到此 savepoint.。嵌套事务是外部事务的一部分, 仅仅有外部事务结束后它才会被提交。

由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大差别在于, PROPAGATION_REQUIRES_NEW 全然是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 假设外部事务 commit,
潜套事务也会被 commit, 这个规则相同适用于 roll back.

Java代码  

  1. //test1配置PROPAGATION_REQUIRED事务属性
  2. public void test1() throws Exception{
  3. avInfoTaskTunnel.insertAvInfoTask();
  4. otherService.test2();  //PROPAGATION_NESTED事务属性
  5. }
  6. //otherService.test2()
  7. public void test2() throws Exception{
  8. avRequestTunnel.insertAvRequest();
  9. }

上述情况。假设otherService.test2()配置PROPAGATION_REQUIRES_NEW事务属性。这样test1()回滚,可是test2()正常提交,由于这是两个事务。可是假设otherService.test2()配置PROPAGATION_NESTED事务属性。然后test1()和test2()将回滚。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

时间: 2024-08-02 17:10:21

spring交易声明的几个传播特性的相关文章

spring事务声明的几种传播特性

最近遇到了一个spring事务导致的问题,所以写了几个小程序了解了一下事务的传播特性,下面分别举例子分别看看事务的传播特性. 事务的几种传播特性 1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务.如果没有事务则开启 Java代码   /** * TransactionTestService     test1和test2配有事务(PROPAGATION_REQUIRED) */ public interface TransactionTestService {

spring传播特性解惑

之前一直看spring事务传播特性,搞不明白何为传播特性,最近仔细找了些资料研究发现,传播特性其实就是多个事务方法相互调用时,事务如何在这些方法间传播. Spring 支持 7 种事务传播行为: PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中.这是最常见的选择. PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行. PROPAGATION_MANDATORY 使用当前的事务,如果当前没

Spring事务传播特性的浅析——事务方法嵌套调用的迷茫

Spring事务传播机制回顾 Spring事务一个被讹传很广说法是:一个事务方法不应该调用另一个事务方法,否则将产生两个事务.结果造成开发人员在设计事务方法时束手束脚,生怕一不小心就踩到地雷. 其实这是不认识Spring事务传播机制而造成的误解,Spring对事务控制的支持统一在TransactionDefinition类中描述,该类有以下几个重要的接口方法: int getPropagationBehavior():事务的传播行为 int getIsolationLevel():事务的隔离级别

什么是事务、事务特性、事务隔离级别、spring事务传播特性

1.什么是事务: 事务是程序中一系列严密的操作,所有操作执行必须成功完成,否则在每个操作所做的更改将会被撤销,这也是事务的原子性(要么成功,要么失败). 2.事务特性: 事务特性分为四个:原子性(Atomicity).一致性(Consistency).隔离性(Isolation).持续性(Durability)简称ACID. 原子性(Atomicity):事务是数据库逻辑工作单元,事务中包含的操作要么都执行成功,要么都执行失败. 一致性(Consistency):事务执行的结果必须是使数据库数据

Spring事务的传播特性和隔离级别

事务的几种传播特性1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务.如果没有事务则开启2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务.如果没有事务,则非事务的执行3. PROPAGATION_MANDATORY: 如果已经存在一个事务,支持当前事务.如果没有一个活动的事务,则抛出异常.4. PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务.如果一个事务已经存在,则将这个存在的事务挂起.5. PROPAGA

事务、事务特性、事务隔离级别、spring事务传播特性

1.什么是事务: 事务是程序中一系列严密的操作,所有操作执行必须成功完成,否则在每个操作所做的更改将会被撤销,这也是事务的原子性(要么成功,要么失败). 2.事务特性: 事务特性分为四个:原子性(Atomicity).一致性(Consistency).隔离性(Isolation).持续性(Durability)简称ACID. 原子性(Atomicity):事务是数据库逻辑工作单元,事务中包含的操作要么都执行成功,要么都执行失败. 一致性(Consistency):事务执行的结果必须是使数据库数据

事务的隔离级别和传播特性

脏读:当一个事务读取另一个事务未提交的内容,之后由于另一个事务出现了异常回滚了事务,结果造成读取的数据不一致 不可重复读:指一个事务多次读取同一数据,而另一个事务多次对数据进行了修改的操作,这样就导致了第一个事务每次读取的数据不一样, 幻读:当事务一对整张表的数据进行操作时对其进行了新增行,而另一个事务对其进行了删除行,而这时事务一本身对其进行了新增行然而发现并没有对其新增行而产生了幻觉 脏读与不可重复读的区别:脏读是对没有提交的数据进行查询,不可重复读是对已经提交的数据进行的查询 不可重复读与

微信的传播特性及传播模式

微信以其零资费.功能多.种类全.方便快捷等优势迅速的获得了广大用户的好评,它的病毒式的传播特性扩展着其用户群,实时交互信息的能力使得用户之间的距离变得更近,微信用户群以一种前所未有的速度增长,是亚洲地区最大用户群体的移动即时通讯软件.本文主要从微信的传播模式.传播特性.传播的正负效应三个角度解读微信的发展. 微信的传播特性和模式 1.传播特性  传播渠道是传播过程的重要中介,传播者利用传播渠道可将选择加工的信息,传递给受传者并引起相应的反应.传播渠道是信息源源不断地传递的重要一环.微信的产生不断

事务相关知识(传播特性,隔离级别,锁)

上接 : EJB事务控制(CMT和BMT两种方式以及JTA事务) 上篇代码: @TransactionAttribute(TransactionAttributeType.REQUIRED)  //设置事务的传播特性为required 上篇文章为什么设置传播特性为: required? 事务的传播特性有7个: 1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务.如果没有事务则开启       2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持