spring传播特性解惑

之前一直看spring事务传播特性,搞不明白何为传播特性,最近仔细找了些资料研究发现,传播特性其实就是多个事务方法相互调用时,事务如何在这些方法间传播。

Spring 支持 7 种事务传播行为:

  • PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
  • PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
  • PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作。

Demo说明(来自http://blog.csdn.net/liovey/article/details/14149137

采用Junit4.10.0+Spring3.2.1+Spring JDBCTemplate,通过注解方式配置事务,代码层次包括主测试类,两个Service对象,事务在Service开启。

概念

本地事务

数据库事务,默认事务为自动提交,因此如果一个业务逻辑类中有多次数据库操作将无法保证事务的一致性。

Spring事务

对本地事务操作的一次封装,相当于把使用JDBC代码开启、提交、回滚事务进行了封装。

上述两个概念会在demo中用到,以方便大家理解代码。

如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。需要JDBC3.0以上支持。

实例Demo

Propagation.REQUIRED

测试入口代码

[java]  view plain copy

  1. <span style="font-size:14px">//会开启事务,在事务范围内使用则使用同一个事务,否则开启新事务
  2. @Test
  3. public void testRequires(){
  4. sService.addStudent();
  5. }</span>

Service代码

[java]  view plain copy

  1. @Transactional(propagation = Propagation.REQUIRED)
  2. public void addStudent(){
  3. <span style="white-space:pre">  </span>String sql = "insert into student(name) values(‘st0‘)";
  4. jdbcTemplate.execute(sql);
  5. tService.addTeacher();
  6. throw new RuntimeException();
  7. }

[java]  view plain copy

  1. @Transactional(propagation = Propagation.REQUIRES)
  2. public void addTeacher(){
  3. String sql = "insert into teacher(name) values (‘t5‘)";
  4. jdbcTemplate.execute(sql);
  5. }

经测试无论在tService还是sService如果不抛出异常,那么数据提交成功,如果抛出异常,数据提交失败。这说明tService和sService使用的是同一个事务,并且只要方法被调用就开启事务。

Propagation.REQUIRES_NEW

测试入口代码

[java]  view plain copy

  1. //无论何时自身都会开启事务
  2. @Test
  3. public void testRequiresNew(){
  4. sService.addStudent5();
  5. }

Service代码

[java]  view plain copy

  1. @Transactional(propagation = Propagation.REQUIRES_NEW)
  2. public void addStudent5(){
  3. String sql = "insert into student(name) values(‘st5‘)";
  4. jdbcTemplate.execute(sql);
  5. tService.addTeacher5();
  6. throw new RuntimeException();
  7. }

[java]  view plain copy

  1. @Transactional(propagation = Propagation.REQUIRES_NEW)
  2. public void addTeacher5(){
  3. String sql = "insert into teacher(name) values (‘t5‘)";
  4. jdbcTemplate.execute(sql);
  5. }

经测试如果在addStudent5中抛出异常,学生数据不能正确提交,教师信息被正确提交。说明sService和tService是在两个独立的事务中运行,并且只要方法被调用就开启事务。

Propagation.SUPPORTS

测试入口代码

[java]  view plain copy

  1. //自身不会开启事务,在事务范围内则使用相同事务,否则不使用事务
  2. @Test
  3. public void testSupport(){
  4. sService.addStudent6();
  5. }

Service代码

[java]  view plain copy

  1. @Transactional(propagation = Propagation.SUPPORTS)
  2. public void addStudent6(){
  3. String sql = "insert into student(name) values(‘st6‘)";
  4. jdbcTemplate.execute(sql);
  5. tService.addTeacher6();
  6. throw new RuntimeException();
  7. }

[java]  view plain copy

  1. @Transactional(propagation = Propagation.SUPPORTS)
  2. public void addTeacher6(){
  3. String sql = "insert into teacher(name) values (‘t6‘)";
  4. jdbcTemplate.execute(sql);
  5. }

经测试如果在addStudent6中抛出异常,学生数据和教师数据都被正确提交。说明sService和tService没有被spring管理和开启事务,而是使用了本地事务,由于本地事务默认自动提交因此数据都提交成功,但它们使用的却不是同一个事务,一旦出现异常将导致数据的不一致。

Propagation.NOT_SUPPORTED

测试入口代码

[java]  view plain copy

  1. //自身不会开启事务,在事务范围内使用挂起事务,运行完毕恢复事务
  2. @Test
  3. public void testNotSupport(){
  4. sService.addStudent4();
  5. }

Service代码

[java]  view plain copy

  1. @Transactional(propagation = Propagation.NOT_SUPPORTED)
  2. public void addStudent4(){
  3. String sql = "insert into student(name) values(‘st4‘)";
  4. jdbcTemplate.execute(sql);
  5. throw new RuntimeException();
  6. }

经测试如果在addStudent4中抛出异常,学生数据正确提交。说明sService没有被spring管理和开启事务,而是使用了本地事务,由于本地事务默认自动提交因此数据都提交成功。

测试入口代码

[java]  view plain copy

  1. //自身不会开启事务,在事务范围内使用挂起事务,运行完毕恢复事务
  2. @Test
  3. public void testNotSupport1(){
  4. sService.addStudent();
  5. }

Service代码

[java]  view plain copy

  1. @Transactional(propagation = Propagation.REQUIRED)
  2. public void addStudent(){
  3. String sql = "insert into student(name) values(‘st0‘)";
  4. jdbcTemplate.execute(sql);
  5. tService.addTeacher4();
  6. }

[java]  view plain copy

  1. @Transactional(propagation = Propagation.NOT_SUPPORTED)
  2. public void addTeacher4(){
  3. String sql = "insert into teacher(name) values (‘t4‘)";
  4. jdbcTemplate.execute(sql);
  5. throw new RuntimeException();
  6. }

经测试如果在addTeacher4中抛出异常,学生数据提交失败,教师数据提交成功。说明sService开启了事务,tService没有开启事务,而是使用了本地事务。

Propagation.MANDATORY

测试入口代码

[java]  view plain copy

  1. //自身不开启事务,必须在事务环境使用否则报错
  2. @Test
  3. public void testMandatory(){
  4. sService.addStudent1();
  5. }

Service代码

[java]  view plain copy

  1. @Transactional(propagation = Propagation.MANDATORY)
  2. public void addStudent1(){
  3. String sql = "insert into student(name) values(‘st1‘)";
  4. jdbcTemplate.execute(sql);
  5. }

经测试代码报错。

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation ‘mandatory‘,没有找到事务环境。

Propagation.NEVER

测试入口代码

[java]  view plain copy

  1. <span style="font-size:14px">//自身不会开启事务,在事务范围使用抛出异常
  2. @Test
  3. public void testNever(){
  4. sService.addStudent();
  5. }</span>

Service代码

[java]  view plain copy

  1. <span style="font-size:14px">@Transactional(propagation = Propagation.REQUIRED)
  2. public void addStudent(){
  3. String sql = "insert into student(name) values(‘st0‘)";
  4. jdbcTemplate.execute(sql);
  5. tService.addTeacher3();
  6. }</span>

[java]  view plain copy

  1. <span style="font-size:14px">@Transactional(propagation = Propagation.NEVER)
  2. public void addTeacher3(){
  3. String sql = "insert into teacher(name) values (‘t3‘)";
  4. jdbcTemplate.execute(sql);
  5. }</span><span style="font-size:18px">
  6. </span>

经测试代码报错,由于sService开启了事务,当调用sService方法时由于其传播特性为never,因此报存在事务错误。

org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation ‘never‘

Propagation.NESTED

测试入口代码

[java]  view plain copy

  1. //如果没有事务环境其特性同Propagation.REQUIRED,否则嵌套运行事务
  2. @Test
  3. public void testNested(){
  4. sService.addStudent2();
  5. }

Service代码

[java]  view plain copy

  1. @Transactional(propagation = Propagation.NESTED)
  2. public void addStudent2(){
  3. String sql = "insert into student(name) values(‘st2‘)";
  4. jdbcTemplate.execute(sql);
  5. tService.addTeacher2();
  6. throw new RuntimeException();
  7. }

[java]  view plain copy

  1. @Transactional(propagation = Propagation.NESTED)
  2. public void addTeacher2(){
  3. String sql = "insert into teacher(name) values (‘t2‘)";
  4. jdbcTemplate.execute(sql);
  5. }

经测试代码报错,教师数据和学生数据都没有提交成功。说明其按照REQUIRED特性运行。对于嵌套事务,大家可以模拟两个数据源,一方的失败不会影响另一方。

以上是所有demo解析。完整的测试代码请在:Spring事务传播特性下载。

另:

大家感兴趣SpringAOP入门和原理,可以在SpringAOP下载。

时间: 2024-11-09 00:19:42

spring传播特性解惑的相关文章

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

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

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

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

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

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

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.传播特性  传播渠道是传播过程的重要中介,传播者利用传播渠道可将选择加工的信息,传递给受传者并引起相应的反应.传播渠道是信息源源不断地传递的重要一环.微信的产生不断

Spring Boot特性(转)

摘要: 1. SpringApplication SpringApplication 类是启动 Spring Boot 应用的入口类,你可以创建一个包含 main() 方法的类,来运行 SpringApplication.run 这个静态方法: public static void main(String... 1. SpringApplication SpringApplication 类是启动 Spring Boot 应用的入口类,你可以创建一个包含 main() 方法的类,来运行 Spri

【转】Spring Boot特性

https://yq.aliyun.com/articles/25530 摘要: 1. SpringApplication SpringApplication 类是启动 Spring Boot 应用的入口类,你可以创建一个包含 main() 方法的类,来运行 SpringApplication. 1. SpringApplication SpringApplication 类是启动 Spring Boot 应用的入口类,你可以创建一个包含 main() 方法的类,来运行 SpringApplic