`
lvwenwen
  • 浏览: 955432 次
  • 性别: Icon_minigender_1
  • 来自: 魔都
社区版块
存档分类
最新评论

Spring事务管理,图解事务传播行为

阅读更多
文章链接:http://www.iteye.com/topic/1122176
9.3.5  事务属性
       事务属性通过TransactionDefinition接口实现定义,主要有事务隔离级别、事务传播行为、事务超时时间、事务是否只读。
       Spring提供TransactionDefinition接口默认实现DefaultTransactionDefinition,可以通过该实现类指定这些事务属性。
事务隔离级别:用来解决并发事务时出现的问题,其使用TransactionDefinition中的静态变量来指定:
         ISOLATION_DEFAULT:默认隔离级别,即使用底层数据库默认的隔离级别;
         ISOLATION_READ_UNCOMMITTED:未提交读;
         ISOLATION_READ_COMMITTED:提交读,一般情况下我们使用这个;
         ISOLATION_REPEATABLE_READ:可重复读;
         ISOLATION_SERIALIZABLE:序列化。

可以使用DefaultTransactionDefinition类的setIsolationLevel(TransactionDefinition. ISOLATION_READ_COMMITTED)来指定隔离级别,其中此处表示隔离级别为提交读,也可以使用或setIsolationLevelName(“ISOLATION_READ_COMMITTED”)方式指定,其中参数就是隔离级别静态变量的名字,但不推荐这种方式。
事务传播行为:Spring管理的事务是逻辑事务,而且物理事务和逻辑事务最大差别就在于事务传播行为,事务传播行为用于指定在多个事务方法间调用时,事务是如何在这些方法间传播的,Spring共支持7种传播行为:


Required:必须有逻辑事务,否则新建一个事务,使用PROPAGATION_REQUIRED指定,表示如果当前存在一个逻辑事务,则加入该逻辑事务,否则将新建一个逻辑事务,如图9-2和9-3所示;

图9-2 Required传播行为

图9-3 Required传播行为抛出异常情况
              在前边示例中就是使用的Required传播行为:
一、在调用userService对象的save方法时,此方法用的是Required传播行为且此时Spring事务管理器发现还没开启逻辑事务,因此Spring管理器觉得开启逻辑事务,
二、在此逻辑事务中调用了addressService对象的save方法,而在save方法中发现同样用的是Required传播行为,因此使用该已经存在的逻辑事务;
三、在返回到addressService对象的save方法,当事务模板类执行完毕,此时提交并关闭事务。
       因此userService对象的save方法和addressService的save方法属于同一个物理事务,如果发生回滚,则两者都回滚。


接下来测试一下该传播行为如何执行吧:
一、正确提交测试,如上一节的测试,在此不再演示;
二、回滚测试,修改AddressServiceImpl的save方法片段:

java代码:
Java代码 
addressDao.save(address); 



java代码:
Java代码 
addressDao.save(address); 
//抛出异常,将标识当前事务需要回滚 
throw new RuntimeException(); 

二、修改UserServiceImpl的save方法片段:

java代码:
Java代码 
addressService.save(user.getAddress()); 



java代码:
Java代码 
try { 
    addressService.save(user.getAddress());//将在同一个事务内执行 
} catch (RuntimeException e) { 

  

如果该业务方法执行时事务被标记为回滚,则不管在此是否捕获该异常都将发生回滚,因为处于同一逻辑事务。

三、修改测试方法片段:

java代码:
Java代码 
userService.save(user); 
Assert.assertEquals(1, userService.countAll()); 
Assert.assertEquals(1, addressService.countAll()); 

为如下形式:


java代码:
Java代码 
try { 
    userService.save(user); 
    Assert.fail(); 
} catch (RuntimeException e) { 

Assert.assertEquals(0, userService.countAll()); 
Assert.assertEquals(0, addressService.countAll()); 

Assert断言中countAll方法都返回0,说明事务回滚了,即说明两个业务方法属于同一个物理事务,即使在userService对象的save方法中将异常捕获,由于addressService对象的save方法抛出异常,即事务管理器将自动标识当前事务为需要回滚。




RequiresNew:创建新的逻辑事务,使用PROPAGATION_REQUIRES_NEW指定,表示每次都创建新的逻辑事务(物理事务也是不同的)如图9-4和9-5所示:

图9-4 RequiresNew传播行为

图9-5 RequiresNew传播行为并抛出异常
接下来测试一个该传播行为如何执行吧:
1、将如下获取事务模板方式

java代码:
Java代码 
TransactionTemplate transactionTemplate = TransactionTemplateUtils.getDefaultTransactionTemplate(txManager); 

       替换为如下形式,表示传播行为为RequiresNew:

java代码:
Java代码 
TransactionTemplate transactionTemplate = TransactionTemplateUtils.getTransactionTemplate( 
        txManager,  
        TransactionDefinition.PROPAGATION_REQUIRES_NEW,  
        TransactionDefinition.ISOLATION_READ_COMMITTED); 

2、执行如下测试,发现执行结果是正确的:

java代码:
Java代码 
userService.save(user); 
Assert.assertEquals(1, userService.countAll()); 
Assert.assertEquals(1, addressService.countAll()); 

3、修改UserServiceImpl的save方法片段

java代码:
Java代码 
userDao.save(user);        
user.getAddress().setUserId(user.getId()); 
addressService.save(user.getAddress()); 

为如下形式,表示userServiceImpl类的save方法将发生回滚,而AddressServiceImpl类的方法由于在抛出异常前执行,将成功提交事务到数据库:


java代码:
Java代码 
userDao.save(user);        
user.getAddress().setUserId(user.getId()); 
addressService.save(user.getAddress()); 
throw new RuntimeException(); 

4、修改测试方法片段:

java代码:
Java代码 
userService.save(user); 
Assert.assertEquals(1, userService.countAll()); 
Assert.assertEquals(1, addressService.countAll()); 

为如下形式:


java代码:
Java代码 
try { 
    userService.save(user); 
    Assert.fail(); 
} catch (RuntimeException e) { 

Assert.assertEquals(0, userService.countAll()); 
Assert.assertEquals(1, addressService.countAll()); 

Assert断言中调用userService对象countAll方法返回0,说明该逻辑事务作用域回滚,而调用addressService对象的countAll方法返回1,说明该逻辑事务作用域正确提交。因此这是不正确的行为,因为用户和地址应该是一一对应的,不应该发生这种情况,因此此处正确的传播行为应该是Required。

该传播行为执行流程(正确提交情况):
一、当执行userService对象的save方法时,由于传播行为是RequiresNew,因此创建一个新的逻辑事务(物理事务也是不同的);
二、当执行到addressService对象的save方法时,由于传播行为是RequiresNew,因此首先暂停上一个逻辑事务并创建一个新的逻辑事务(物理事务也是不同的);
三、addressService对象的save方法执行完毕后,提交逻辑事务(并提交物理事务)并重新恢复上一个逻辑事务,继续执行userService对象的save方法内的操作;
四、最后userService对象的save方法执行完毕,提交逻辑事务(并提交物理事务);
五、userService对象的save方法和addressService对象的save方法不属于同一个逻辑事务且也不属于同一个物理事务。




Supports:支持当前事务,使用PROPAGATION_SUPPORTS指定,指如果当前存在逻辑事务,就加入到该逻辑事务,如果当前没有逻辑事务,就以非事务方式执行,如图9-6和9-7所示:

图9-6 Required+Supports传播行为

       图9-7 Supports+Supports传播行为




NotSupported:不支持事务,如果当前存在事务则暂停该事务,使用PROPAGATION_NOT_SUPPORTED指定,即以非事务方式执行,如果当前存在逻辑事务,就把当前事务暂停,以非事务方式执行,如图9-8和9-9所示:

       图9-8 Required+NotSupported传播行为

       图9-9 Supports+NotSupported传播行为




Mandatory:必须有事务,否则抛出异常,使用PROPAGATION_MANDATORY指定,使用当前事务执行,如果当前没有事务,则抛出异常(IllegalTransactionStateException),如图9-10和9-11所示:



       图9-10 Required+Mandatory传播行为

       图9-11 Supports+Mandatory传播行为




Never:不支持事务,如果当前存在是事务则抛出异常,使用PROPAGATION_NEVER指定,即以非事务方式执行,如果当前存在事务,则抛出异常(IllegalTransactionStateException),如图9-12和9-13所示:

       图9-12 Required+Never传播行为

       图9-13 Supports+Never传播行为





Nested:嵌套事务支持,使用PROPAGATION_NESTED指定,如果当前存在事务,则在嵌套事务内执行,如果当前不存在事务,则创建一个新的事务,嵌套事务使用数据库中的保存点来实现,即嵌套事务回滚不影响外部事务,但外部事务回滚将导致嵌套事务回滚,如图9-14和9-15所示:

       图9-14 Required+Nested传播行为

图9-15 Nested+Nested传播行为



Nested和RequiresNew的区别:
1、  RequiresNew每次都创建新的独立的物理事务,而Nested只有一个物理事务;
2、  Nested嵌套事务回滚或提交不会导致外部事务回滚或提交,但外部事务回滚将导致嵌套事务回滚,而 RequiresNew由于都是全新的事务,所以之间是无关联的;
3、  Nested使用JDBC 3的保存点实现,即如果使用低版本驱动将导致不支持嵌套事务。
使用嵌套事务,必须确保具体事务管理器实现的nestedTransactionAllowed属性为true,否则不支持嵌套事务,如DataSourceTransactionManager默认支持,而HibernateTransactionManager默认不支持,需要我们来开启。
对于事务传播行为我们只演示了Required和RequiresNew,其他传播行为类似,如果对这些事务传播行为不太会使用,请参考chapter9包下的TransactionTest测试类中的testPropagation方法,方法内有详细示例。

事务超时:设置事务的超时时间,单位为秒,默认为-1表示使用底层事务的超时时间;
         使用如setTimeout(100)来设置超时时间,如果事务超时将抛出org.springframework.transaction.TransactionTimedOutException异常并将当前事务标记为应该回滚,即超时后事务被自动回滚;
         可以使用具体事务管理器实现的defaultTimeout属性设置默认的事务超时时间,如DataSourceTransactionManager. setDefaultTimeout(10)。

事务只读:将事务标识为只读,只读事务不修改任何数据;
         对于JDBC只是简单的将连接设置为只读模式,对于更新将抛出异常;
         而对于一些其他ORM框架有一些优化作用,如在Hibernate中,Spring事务管理器将执行“session.setFlushMode(FlushMode.MANUAL)”即指定Hibernate会话在只读事务模式下不用尝试检测和同步持久对象的状态的更新。
         如果使用设置具体事务管理的validateExistingTransaction属性为true(默认false),将确保整个事务传播链都是只读或都不是只读,如图9-16是正确的事务只读设置,而图9-17是错误的事务只读设置:

图9-16 正确的事务只读设置


图9-17 错误的事务只读设置
如图10-17,对于错误的事务只读设置将抛出IllegalTransactionStateException异常,并伴随“Participating transaction with definition [……] is not marked as read-only……”信息,表示参与的事务只读属性设置错误。


详见博客
【第九章】 Spring的事务 之 9.3 编程式事务 ——跟我学spring3

声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
想进外企,出国,跳槽,找工作?英语不好,快来充电吧
100万现金奖培训出来的程序员

返回顶楼     
jinnianshilongnian
等级:

文章: 226
积分: 700

   发表时间:10 小时前   最后修改:9 小时前 引用 收藏

代理方式下的自我调用


图9-18 代理方式实现事务管理
       如图9-18,代理方式实现事务管理只是将硬编码的事务管理代码转移到代理中去由代理实现,在代理中实现事务管理。

       注:在代理模式下,默认只有通过代理对象调用的方法才能应用相应的事务属性,而在目标方法内的“自我调用”是不会应用相应的事务属性的,即被调用方法不会应用相应的事务属性,而是使用调用方法的事务属性。

如图9-19所示,在目标对象targetUserService的save方法内调用事务方法“this.otherTransactionMethod()”将不会应用配置的传播行为RequriesNew,开启新事务,而是使用save方法的已开启事务,如果非要这样使用如下方式实现:

1、  修改TransactionProxyFactoryBean配置定义,添加exposeProxy属性为true;
2、  在业务方法内通过代理对象调用相应的事务方放,如 “((IUserService)AopContext.currentProxy()).otherTransactionMethod()”即可应用配置的事务属性。
3、  使用这种方式属于侵入式,不推荐使用,除非必要。

图9-19 代理方式下的自我调用
分享到:
评论

相关推荐

    Spring事务管理Demo

    Spring事务管理的目的是确保数据的一致性和完整性,尤其是在多操作、多资源的环境中。本Demo将深入探讨Spring如何实现事务的管理。 首先,Spring提供了两种主要的事务管理方式:编程式事务管理和声明式事务管理。 ...

    Spring中事务的传播属性详解

    本文将详细介绍Spring中的事务传播属性,并通过具体的例子来解释每种传播行为的特点。 #### 二、事务传播属性概述 事务传播行为(Propagation)定义了当一个事务方法被另一个事务方法调用时的行为。在Spring中,...

    spring 事务传播 demo

    本示例“spring 事务传播 demo”将聚焦于Spring的事务传播行为,这是在多个方法调用中控制事务边界的关键概念。下面我们将详细讨论相关知识点。 首先,事务传播行为是指当一个被@Transactional注解的方法被另一个@...

    Spring事务管理开发必备jar包

    本资源包提供了进行Spring事务管理开发所需的所有关键库,包括框架基础、核心组件、AOP(面向切面编程)支持、日志处理、编译工具以及与数据库交互的相关jar包。下面将对这些知识点进行详细解释: 1. **Spring框架*...

    Spring事务管理失效原因汇总

    总结来说,Spring事务管理失效的原因是多方面的,涵盖从代理模式原理到AOP的实现细节,再到异常处理机制,以及事务传播和隔离级别的配置等多个层面。开发者需要深入理解Spring框架的内部机制,才能在实际开发中有效...

    spring 事务管理的理解

    Spring 框架是Java开发中的一个核心组件,尤其在企业级应用中广泛使用。它提供了许多特性,其中一项...在实际开发中,结合声明式事务管理、事务传播行为、隔离级别和回滚规则,可以有效地确保数据的完整性和一致性。

    Spring事务管理的jar包

    Spring事务管理分为编程式事务管理和声明式事务管理两种方式。编程式事务管理通过使用PlatformTransactionManager接口的begin、commit、rollback等方法直接控制事务的生命周期,这种方式灵活但容易导致代码过于繁琐...

    Spring事务传播Demo.zip

    本篇将基于"Spring事务传播Demo"来深入探讨Spring事务管理和传播行为。 首先,我们需要理解什么是事务。在数据库操作中,事务是一组操作,这些操作要么全部执行,要么全部不执行,以确保数据的一致性和完整性。在...

    spring事务管理

    ### Spring事务管理详解 #### 一、事务管理基础概念 在深入探讨Spring事务管理之前,我们需要先理解什么是事务。事务可以被定义为一系列的操作集合,这些操作作为一个整体被提交或回滚。简单来说,事务就是一个不...

    Spring事务流程图

    5. **事务传播行为**:Spring提供了七种事务传播行为,如REQUIRED(默认)、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED,它们决定了事务如何在方法调用之间传播。 时序图是一种UML建模工具...

    Spring事务传播机制.docx

    Spring 事务传播机制 Spring 事务传播机制是指在 Spring 框架中,事务的传播和嵌套机制。当我们在使用 Spring 所提供的事务功能时,如果是仅仅处理单个的事务,是比较容易把握事务的提交与回滚,不过一旦引入嵌套...

    spring 自定义事务管理器,编程式事务,声明式事务@Transactional使用

    在Spring框架中,事务管理是核心功能之一,它确保了数据操作的一致性和完整性。本教程将深入探讨如何在Spring中实现自定义事务管理器...这将加深你对Spring事务管理的理解,帮助你在实际项目中更加熟练地运用这些技术。

    SPRING事务传播特性&事务隔离级别

    ### Spring 事务传播特性和事务隔离级别详解 #### 一、Spring 事务传播特性 在进行多层服务架构设计时,事务的管理尤其重要。为了确保数据的一致性,Spring 提供了一种灵活的方式来控制事务的传播行为。下面详细...

    spring 事务传播

    通过上述对Spring事务传播行为的详细介绍,我们可以看出,正确理解和应用这些传播行为对于构建健壮的事务管理机制至关重要。每种传播行为都有其特定的应用场景和限制条件,开发者应根据具体的业务逻辑和需求来合理...

    实验 spring 声明事务

    实验 "Spring 声明事务" 是 Java 高级编程中的一个重要环节,旨在让学生掌握 Spring 框架中声明式事务管理的配置和使用。在实际应用中,事务管理是确保数据一致性、完整性和可靠性的关键组件。Spring 提供了声明式...

    Spring在Transaction事务传播行为种类

    Spring框架提供了丰富的事务管理功能,其中包括了事务传播行为(Propagation Behavior)。本文将详细介绍Spring框架中定义的七种不同的事务传播行为类型及其应用场景。 #### 二、事务传播行为概述 事务传播行为是指...

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

    Spring提供了七种事务传播特性,每一种都有其特定的场景适用性。 1. **PROPAGATION_REQUIRED** - 这是最常用的传播行为。当使用此传播行为时,如果当前存在事务,则在该事务中执行;如果没有,则创建一个新的事务...

    Spring事务管理.pdf

    Spring事务管理.pdf 1.资料 2.本地事务与分布式事务 3.编程式模型 4.宣告式模型

Global site tag (gtag.js) - Google Analytics