Spring事务传播机制回顾
Spring事务一个被讹传很广说法是:一个事务方法不应该调用另一个事务方法,否则将产生两个事务。结果造成开发人员在设计事务方法时束手束脚,生怕一不小心就踩到地雷。
其实这是不认识Spring事务传播机制而造成的误解,Spring对事务控制的支持统一在TransactionDefinition类中描述,该类有以下几个重要的接口方法:
- int getPropagationBehavior():事务的传播行为
- int getIsolationLevel():事务的隔离级别
- int getTimeout():事务的过期时间
- boolean isReadOnly():事务的读写特性
很明显,除了事务的传播行为外,事务的其他特性Spring是借助底层资源的功能来完成的,Spring无非只充当个代理的角色。但是事务的传播行为却是Spring凭借自身的框架提供的功能,是Spring提供给开发者最珍贵的礼物,讹传的说法玷污了Spring事务框架最美丽的光环。
所谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。Spring支持以下7种事务传播行为。
- PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务,就加入到这个事务中。这是最常见的选择。
- PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
- PROPAGATION_MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
- PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
- PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
- PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
Spring默认的事务传播行为是PROPAGATION_REQUIRED,它适合绝大多数的情况,如果多个ServiveX#methodX()均工作在事务环境下(即均被Spring事务增强),且程序中存在如下的调用链:Service1#method1()->Service2#method2()->Service3#method3(),那么这3个服务类的3个方法通过Spring的事务传播机制都工作在同一个事务中。
相互嵌套的服务方法
我们来看一下实例,UserService#logon()方法内部调用了UserService#updateLastLogon Time()和ScoreService#addScore()方法,这两个类都继承于BaseService。它们之间的类结构如下图所示:
UserService#logon()方法内部调用了ScoreService#addScore()的方法,两者都分别通过Spring AOP进行了事务增强,则它们工作于同一事务中。来看具体的代码:
- package com.baobaotao.nestcall;
- …
- @Service("userService")
- public class UserService extends BaseService {
- @Autowired
- private JdbcTemplate jdbcTemplate;
-
- @Autowired
- private ScoreService scoreService;
-
-
- public void logon(String userName) {
- System.out.println("before userService.updateLastLogonTime...");
- updateLastLogonTime(userName);
- System.out.println("after userService.updateLastLogonTime...");
-
- System.out.println("before scoreService.addScore...");
- scoreService.addScore(userName, 20);
- System.out.println("after scoreService.addScore...");
-
- }
- public void updateLastLogonTime(String userName) {
- String sql = "UPDATE t_user u SET u.last_logon_time = ? WHERE user_name =?";
- jdbcTemplate.update(sql, System.currentTimeMillis(), userName);
- }
UserService中注入了ScoreService的Bean,而ScoreService的代码如下所示:
- package com.baobaotao.nestcall;
- …
- @Service("scoreUserService")
- public class ScoreService extends BaseService{
-
- @Autowired
- private JdbcTemplate jdbcTemplate;
-
- public void addScore(String userName, int toAdd) {
- String sql = "UPDATE t_user u SET u.score = u.score + ? WHERE user_name =?";
- jdbcTemplate.update(sql, toAdd, userName);
- }
- }
通过Spring配置为ScoreService及UserService中所有公有方法都添加Spring AOP的事务增强,让UserService的logon()和updateLastLogonTime()及ScoreService的addScore()方法都工作于事务环境下。下面是关键的配置代码:
- <?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:context="http://www.springframework.org/schema/context"
- xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="http:
- http:
- <context:component-scan base-package="com.baobaotao.nestcall"/>
- …
- <bean id="jdbcManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
- p:dataSource-ref="dataSource"/>
-
- <!--①通过以下配置为所有继承BaseService类的所有子类的所有public方法都添加事务增强-->
- <aop:config proxy-target-class="true">
- <aop:pointcut id="serviceJdbcMethod"
- expression="within(com.baobaotao.nestcall.BaseService+)"/>
- <aop:advisor pointcut-ref="serviceJdbcMethod" advice-ref="jdbcAdvice" order="0"/>
- </aop:config>
- <tx:advice id="jdbcAdvice" transaction-manager="jdbcManager">
- <tx:attributes>
- <tx:method name="*"/>
- </tx:attributes>
- </tx:advice>
- </beans>
将日志级别设置为DEBUG,启动Spring容器并执行UserService#logon()的方法,仔细观察如下输出日志:
- before userService.logon method...
-
- //①创建了一个事务
- Creating new transaction with name [com.baobaotao.nestcall.UserService.logon]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
- Acquired Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] for JDBC transaction
- Switching JDBC Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] to manual commit
- before userService.updateLastLogonTime...
-
- <!--②updateLastLogonTime()和logon()在同一个Bean中,并未发生加入已存在事务上下文的
- 动作,而是“天然”地工作于相同的事务上下文-->
- Executing prepared SQL update
- Executing prepared SQL statement [UPDATE t_user u SET u.last_logon_time = ? WHERE user_name =?]
- SQL update affected 1 rows
- after userService.updateLastLogonTime...
- before scoreService.addScore...
-
- //③ScoreService#addScore方法加入到①处启动的事务上下文中
- Participating in existing transaction
- Executing prepared SQL update
- Executing prepared SQL statement [UPDATE t_user u SET u.score = u.score + ? WHERE user_name =?]
- SQL update affected 1 rows
- after scoreService.addScore...
- Initiating transaction commit
- Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver]
- …
- after userService.logon method...
从上面的输出日志中,可以清楚地看到Spring为UserService#logon()方法启动了一个新的事务,而UserSerive#updateLastLogonTime()和UserService#logon()是在相同的类中,没有观察到有事务传播行为的发生,其代码块好像“直接合并”到UserService#logon()中。
然而在执行到ScoreService#addScore()方法时,我们就观察到发生一个事务传播的行为:" Participating in existing transaction ",这说明ScoreService#addScore()添加到UserService#logon()的事务上下文中,两者共享同一个事务。所以最终的结果是UserService的logon()、updateLastLogonTime()以及ScoreService的addScore都工作于同一事务中。
注:以上内容摘自《Spring 3.x企业应用开发实战》
本文来源于:http://blog.csdn.net/hy6688_/article/details/44763869
分享到:
相关推荐
通过代码解析spring传播特性,包括 1、Propagation.REQUIRED 方法被调用时自动开启事务,在事务范围内使用则使用同一个事务,否则开启新事务。 2、Propagation.REQUIRES_NEW 无论何时自身都会开启事务 3、...
### Spring 事务传播特性和事务隔离级别详解 #### 一、Spring 事务传播特性 在进行多层服务架构设计时,事务的管理尤其重要。为了确保数据的一致性,Spring 提供了一种灵活的方式来控制事务的传播行为。下面详细...
本示例“spring 事务传播 demo”将聚焦于Spring的事务传播行为,这是在多个方法调用中控制事务边界的关键概念。下面我们将详细讨论相关知识点。 首先,事务传播行为是指当一个被@Transactional注解的方法被另一个@...
Spring框架提供了多种事务传播特性,用于控制事务在方法调用之间的传播方式。这些传播特性定义了当一个事务方法调用另一个事务方法时的行为: 1. **Propagation_Required**:如果当前存在事务,则继续使用该事务;...
Spring提供了七种事务传播特性,每一种都有其特定的场景适用性。 1. **PROPAGATION_REQUIRED** - 这是最常用的传播行为。当使用此传播行为时,如果当前存在事务,则在该事务中执行;如果没有,则创建一个新的事务...
事务传播行为(Propagation)定义了当一个事务方法被另一个事务方法调用时的行为。在Spring中,这些行为可以通过`TransactionDefinition`接口中的常量来指定。具体来说,`TransactionDefinition`定义了以下七种传播...
在Spring框架中,事务管理是核心特性之一,用于确保数据操作的一致性和完整性。当一个方法(A方法)内部调用另一个方法(B方法)时,可能会遇到事务控制的复杂情况。本示例代码旨在解决在A方法内部调用B方法时的回滚...
Spring 事务传播机制是指在 Spring 框架中,事务的传播和嵌套机制。当我们在使用 Spring 所提供的事务功能时,如果是仅仅处理单个的事务,是比较容易把握事务的提交与回滚,不过一旦引入嵌套事务后,多个事务的回滚...
在Java应用开发中,特别是使用Spring框架时,开发者可以通过配置不同的事务传播行为来控制事务如何在方法调用之间传播。这些传播行为对于理解并正确实现业务逻辑至关重要。 #### 二、事务传播特性的种类 根据给定...
在"Spring事务传播Demo"中,我们可能看到如何在不同传播行为下,一个事务方法被另一个事务方法调用时,事务是如何管理和传播的。例如,一个PROPAGATION_REQUIRED的方法调用了一个PROPAGATION_REQUIRES_NEW的方法,...
事务传播行为是指当一个事务方法调用另一个事务方法时,如何处理这些事务之间的关系。Spring定义了一系列的传播行为选项,以便开发者能够根据具体的业务需求灵活地控制事务的行为。 ##### 1. PROPAGATION_REQUIRED ...
事务传播特性&事务隔离级别 事务传播特性是指在 Java 中,事务的传播行为,即在多个事务之间如何交互和传播。Java 中有七种事务传播特性,分别是: 1. PROPAGATION_REQUIRED:如果存在一个事务,则支持当前事务。...
在Spring框架中,事务管理是核心特性之一,它允许开发者以声明式的方式处理数据库操作的事务性。...在实际应用中,根据业务需求选择合适的事务传播行为,能够有效控制事务的粒度和复杂性,保证数据的一致性和完整性。
Spring通过`@Transactional`注解可以方便地设置事务传播行为和隔离级别,例如: ```java @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED) public void ...
Spring事务传播属性是这一机制的关键组成部分,它定义了在一个事务方法被另一个事务方法调用时,应该如何处理事务的边界。在深入理解Spring事务传播属性之前,我们首先需要了解Spring中的事务管理模型,包括编程式...
在本篇“Spring.NET学习笔记16——事务管理Demo源码”中,我们将深入探讨Spring.NET的事务管理机制及其实际应用。 事务管理是软件开发中的关键部分,它确保数据库操作的一致性和完整性。Spring.NET通过其事务管理...
事务传播行为(Transaction Propagation)是Spring事务管理中一个关键的概念,用于定义在一个事务方法被调用时,如何与当前运行的事务进行交互。本文将深入探讨“Spring事物传播测试表”所涉及的知识点。 首先,...
事务传播行为定义了当一个事务方法被另一个事务方法调用时,如何处理事务的行为。以下是Spring定义的七种事务传播行为: 1. **PROPAGATION_REQUIRED** - **含义**:表示当前方法必须运行在事务中。如果当前事务...
Spring.NET事务配置模板。 原文出处:http://www.cnblogs.com/GoodHelper/archive/2009/11/16/SpringNet_Transaction.html
在Spring中,事务的传播特性(Transaction Propagation)决定了在一个事务方法被调用时,另一个事务方法应该如何运行。例如,PROPAGATION_REQUIRED表示如果当前存在事务,则加入到当前事务,如果当前没有事务,则...