`
dorishy
  • 浏览: 11002 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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

阅读更多

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

 

        事务的几种传播特性

1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务。如果没有事务则开启
/**
 * TransactionTestService     test1和test2配有事务(PROPAGATION_REQUIRED) */
public interface TransactionTestService {
    //事务属性 PROPAGATION_REQUIRED
    public void test1() throws Exception{
        avInfoTaskTunnel.insertAvInfoTask();
        test2();
    }
    //事务属性 PROPAGATION_REQUIRED
    public void test2() throws Exception{
        avRequestTunnel.insertAvRequest();
        throw new Exception();
    }
}
 
/**
 * main
 */
public class TransactionTestMain {
 
    public static void main(String[] args) throws Exception{
        TransactionTestService transactionTestService = (TransactionTestService)context.getBean("transactionTestService");
        try {
            transactionTestService.test1();
        } catch (Exception e) {
        }
    }
}

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

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

//test1()中捕获test2()抛出的异常
    public void test1() throws Exception{
        avInfoTaskTunnel.insertAvInfoTask();
        try {
            test2();
        }catch (Exception e) {
        }
 
    }

       最后的结果test2()也将会正常的写入。其实,上面情况中如果只是test1()配有PROPAGATION_REQUIRED事务属性,test2()不配置任何事务属性,发生的结果也是一致的。上面的情形相当于:

public static void main(String[] args) throws Exception{
        Connection con = null;
        try {
            con=getConnection();
            con.setAutoCommit(false);
            transactionTestService.test1(); //test1()和test2()处于同一事务之中
            con.commit();
        } catch (Exception e) {
            con.rollback();
        } finally {
            closeCon();
        }
    }

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

//main函数不变,test1()中调用test2()地方换成调用另一个类中配有PROPAGATION_REQUIRED事务属性的方法
    //不对otherService.test2()捕获异常的情形就没必要说了,必定都回滚。
    public void test1() throws Exception{
        avInfoTaskTunnel.insertAvInfoTask();
        try {
            otherService.test2();  //PROPAGATION_REQUIRED事务属性
        } catch (Exception e) {
        }
    }
 
    //otherService.test2()
    public void test2() throws Exception{
        avRequestTunnel.insertAvRequest();
        throw new Exception();
    }

         上述同样捕获了异常,但是结果会怎样呢? 结果有点出乎意料,与之前test1(),test2()处于同一类的情形不同,这个时候,两个方法都将回滚,并且在调用test1()的地方会抛出下面异常。这是由于子事务在回滚的时候已经将主事务标记成了rollback-only,这样导致主事务在提交的时候就会抛出下面这个异常。 另外:如果otherService.test2()没有配置任何事务属性,那么test2()抛出异常的时候,将导致test1()和test2()都回滚。

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

        上述情况网上查询到一种解决方式是在transactionManager中将globalRollbackOnParticipationFailure 设置为false(默认是true)。但是这样又带来另一个问题,子事务也给一并提交了(这个时候子事务产生异常,不想提交),具体的解决方式还没找到,但是我觉得不应该将这两个配置在同一事务中。

<bean id="transactionManager"    
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource">
            <ref local="dataSource" />
        </property>
        <property name="globalRollbackOnParticipationFailure" value="false" /> 
    </bean>

 

2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
//TransactionTestService     test1()配有事务(PROPAGATION_SUPPORTS)
    public void test1() throws Exception{
        avInfoTaskTunnel.insertAvInfoTask();
        throw new Exception();
    }
 
 
/**
 * main
 */
    public class TransactionTestMain {
 
        public static void main(String[] args) throws Exception{
            TransactionTestService transactionTestService = (TransactionTestService)context.getBean("transactionTestService");
            try {
                transactionTestService.test1();
            } catch (Exception e) {
            }
       }
    }

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

//PROPAGATION_REQUIRED事务属性
    public void test1() throws Exception{
        avInfoTaskTunnel.insertAvInfoTask();
        test2();
    }
    //PROPAGATION_SUPPORTS事务属性
    public void test2() throws Exception{
        avRequestTunnel.insertAvRequest();
        throw new Exception();
    }

 

  3. PROPAGATION_MANDATORY: 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

 

//情形1:PROPAGATION_REQUIRED事务属性  情形2:不配任何事务属性
    public void test1() throws Exception{
        avInfoTaskTunnel.insertAvInfoTask();
        otherService.test2();
    }
    //otherService的test2()配置PROPAGATION_MANDATORY事务属性
    public void test2() throws Exception {
        avRequestTunnel.insertAvRequest();
        throw new Exception();
    }
 
//test1()处于情形2时抛出异常,test2()不能够提交,但是test1()却是可以成功提交的
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: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
//情形1:PROPAGATION_REQUIRED事务属性  情形2:不配任何事务属性
    public void test1() throws Exception{
        avInfoTaskTunnel.insertAvInfoTask();
        otherService.test2();
    }
    //otherService的test2()配置PROPAGATION_REQUIRES_NEW事务属性
    public void test2() throws Exception {
        avRequestTunnel.insertAvRequest();
        throw new Exception();
    }

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

//test1配置PROPAGATION_REQUIRED事务属性
    public void test1() throws Exception{
        avInfoTaskTunnel.insertAvInfoTask();
            otherService.test2();  //PROPAGATION_REQUIRES_NEW事务属性
    }
 
    //otherService.test2()
    public void test2() throws Exception{
        avRequestTunnel.insertAvRequest();
        throw new Exception();
    }

         如果是在同一事务中,那么情形将同于讲述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: 总是非事务地执行,并挂起任何存在的事务。
//test1配置PROPAGATION_REQUIRED事务属性
    public void test1() throws Exception{
        avInfoTaskTunnel.insertAvInfoTask();
            otherService.test2();  //PROPAGATION_NOT_SUPPORTED事务属性
    }
 
    //otherService.test2()
    public void test2() throws Exception{
        avRequestTunnel.insertAvRequest();
        throw new Exception();
    }

         如果otherService.test2() 没有配置事务属性,那么test2()抛出异常时,test1()和test2()都回滚。但是现在test2()配置了PROPAGATION_NOT_SUPPORTED事务属性,那么test2()将以非事务运行,而test1()继续运行在事务中,也就是说,此时,test1()回滚,test2()正常提交。注意:如果test1()和test2()在同一类中,那么test2()的PROPAGATION_NOT_SUPPORTED失效。

 

6. PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常
//test1配置PROPAGATION_REQUIRED事务属性
    public void test1() throws Exception{
        avInfoTaskTunnel.insertAvInfoTask();
            otherService.test2();  //PROPAGATION_NEVER事务属性
    }
 
    //otherService.test2()
    public void test2() throws Exception{
        avRequestTunnel.insertAvRequest();
        throw new Exception();
    }
//test1()配置PROPAGATION_REQUIRED事务属性, otherService.test2()配置PROPAGATION_NEVER事务属性,将抛下面异常:
org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

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

 

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

        最容易弄混淆的其实是 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.

//test1配置PROPAGATION_REQUIRED事务属性
    public void test1() throws Exception{
        avInfoTaskTunnel.insertAvInfoTask();
            otherService.test2();  //PROPAGATION_NESTED事务属性
    }
 
    //otherService.test2()
    public void test2() throws Exception{
        avRequestTunnel.insertAvRequest();
    }

         上述情况,如果otherService.test2()配置PROPAGATION_REQUIRES_NEW事务属性,这样test1()回滚,但是test2()正常提交,因为这是两个事务。但是如果otherService.test2()配置PROPAGATION_NESTED事务属性,那么test1()和test2()都将回滚。

2
1
分享到:
评论
2 楼 851228082 2015-09-29  
851228082 写道
   但是,如果test1()方法对调用test2()时捕获异常,结果会是怎样的呢? test1应该能正常写入没问题,那么test2呢?

这个应该会出现异常的,org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

test2中将事务标志为回滚,test1中commit时,会出现异常



楼主,sorry,我说错了。你说的是正确的。如果test1、test2不在同一个类中才会出现异常
1 楼 851228082 2015-09-29  
   但是,如果test1()方法对调用test2()时捕获异常,结果会是怎样的呢? test1应该能正常写入没问题,那么test2呢?

这个应该会出现异常的,org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

test2中将事务标志为回滚,test1中commit时,会出现异常

相关推荐

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

    Spring事务的传播特性和隔离级别 事务的几种传播特性详细介绍

    spring事务几种传播方式

    本文介绍spring事务传播的几种方式

    spring事物的7大传播机制,5个隔离机制

    上文理解到对spring事物,事物的隔离机制,这片具体说下事物的传播机制和隔离机制

    高级开发spring面试题和答案.pdf

    传播特性有几种?7种; 某一个事务嵌套另一个事务的时候怎么办? REQUIRED_NEW和REQUIRED区别 Spring的事务是如何回滚的,实现原理; 抽象类和接口的区别,什么时候用抽象类什么时候用接口; StringBuilder和...

    SpringFramework常见知识点.md

    - Spring依赖注入的方式有几种? - 一个bean的定义包含了什么?(BeanDefinition) - bean的作用域有哪些? - Spring 的扩展点主要有哪些? - Spring如何解决循环依赖? - 事务的传播行为是什么?有哪些? - 什么是AOP...

    leetcode下载-JavaTopic:Java面试题总结

    spring事务7种传播特性和隔离级别的理解? spring boot的启动过程 spring事务实现的原理 aop切面 如何解决spring循环依赖问题? Redis篇: redis持久化的原理(RDB、AOF); redis缓存穿透、缓存雪崩,有没有在实际...

    ssh(structs,spring,hibernate)框架中的上传下载

    Spring针对几个著名的Web服务器的数据源提供了相应的JDBC抽取器:  •WebLogic:WebLogicNativeJdbcExtractor  •WebSphere:WebSphereNativeJdbcExtractor  •JBoss:JBossNativeJdbcExtractor  在定义了JDBC...

    java面试题,180多页,绝对良心制作,欢迎点评,涵盖各种知识点,排版优美,阅读舒心

    【基础】Java 中定义常量的几种方法 25 【基础】什么时候使用字节流?什么时候用字符流? 26 【基础】GBK与UTF-8的区别 26 【基础】static、final、const的区别 26 final: 26 static: 27 【基础】如何实现对象克隆?...

    你的接口,真的能承受高并发吗?

    本文转自公众号【肥朝】 前言 本篇主要讲解的是前阵子的一个...我们先不纠结为什么使用第三种,后面在讲事务传播机制的时候我会专门介绍,我们聚焦一下主题,你现在只要知道,那个是开启事务的意思就行了.我特意用红色和

    javaSE代码实例

    11.1.2 异常的传播过程 198 11.1.3 finally语句块的使用 199 11.1.4 try、catch及finally语句块之间需要注意的问题 201 11.2 异常的层次结构 203 11.2.1 捕获异常 203 11.2.2 未捕获异常 205 11.3 再次...

Global site tag (gtag.js) - Google Analytics