背景介绍
目前系统正在进行代码重构前期预研工作,目标采用spring控制事务以减少开发代码量,提高开发效率。同时避免开发人员编码控制事务所带来的链接没有释放,事务没有提交,出现异常事务没有回滚的Bug。
为保证系统能正确使用Spring控制事务,必须很好的理解其传播特性。在沟通中发现,好多人知道这个概念但是对于事务的实际传播行为往往模棱两可。
基于上述原因,本文采用Demo实例的方式对事务的7大传播特性给出了解析。希望能明确大家对事务传播特性的认识,在以后的工作中成功使用。
Demo说明
采用Junit4.10.0+Spring3.2.1+Spring JDBCTemplate,通过注解方式配置事务,代码层次包括主测试类,两个Service对象,事务在Service开启。
概念
本地事务
数据库事务,默认事务为自动提交,因此如果一个业务逻辑类中有多次数据库操作将无法保证事务的一致性。
Spring事务
对本地事务操作的一次封装,相当于把使用JDBC代码开启、提交、回滚事务进行了封装。
上述两个概念会在demo中用到,以方便大家理解代码。
传播特性
该特性是保证事务是否开启,业务逻辑是否使用同一个事务的保证。当事务在传播过程中会受其影响。其传播特性包括:
1、Propagation.REQUIRED
方法被调用时自动开启事务,在事务范围内使用则使用同一个事务,否则开启新事务。
2、Propagation.REQUIRES_NEW
无论何时自身都会开启事务
3、Propagation.SUPPORTS
自身不会开启事务,在事务范围内则使用相同事务,否则不使用事务
4、Propagation.NOT_SUPPORTED
自身不会开启事务,在事务范围内使用挂起事务,运行完毕恢复事务
5、Propagation.MANDATORY
自身不开启事务,必须在事务环境使用否则报错
6、Propagation.NEVER
自身不会开启事务,在事务范围使用抛出异常
7、Propagation.NESTED
如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。需要JDBC3.0以上支持。
实例Demo
Propagation.REQUIRED
测试入口代码
[java] view plaincopy
<span style="font-size:14px">//会开启事务,在事务范围内使用则使用同一个事务,否则开启新事务
@Test
public void testRequires(){
sService.addStudent();
}</span>
Service代码
[java] view plaincopy
@Transactional(propagation = Propagation.REQUIRED)
public void addStudent(){
<span style="white-space:pre"> </span>String sql = "insert into student(name) values('st0')";
jdbcTemplate.execute(sql);
tService.addTeacher();
throw new RuntimeException();
}
[java] view plaincopy
@Transactional(propagation = Propagation.REQUIRES)
public void addTeacher(){
String sql = "insert into teacher(name) values ('t5')";
jdbcTemplate.execute(sql);
}
经测试无论在tService还是sService如果不抛出异常,那么数据提交成功,如果抛出异常,数据提交失败。这说明tService和sService使用的是同一个事务,并且只要方法被调用就开启事务。
Propagation.REQUIRES_NEW
测试入口代码
[java] view plaincopy
//无论何时自身都会开启事务
@Test
public void testRequiresNew(){
sService.addStudent5();
}
Service代码
[java] view plaincopy
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addStudent5(){
String sql = "insert into student(name) values('st5')";
jdbcTemplate.execute(sql);
tService.addTeacher5();
throw new RuntimeException();
}
[java] view plaincopy
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addTeacher5(){
String sql = "insert into teacher(name) values ('t5')";
jdbcTemplate.execute(sql);
}
经测试如果在addStudent5中抛出异常,学生数据不能正确提交,教师信息被正确提交。说明sService和tService是在两个独立的事务中运行,并且只要方法被调用就开启事务。
Propagation.SUPPORTS
测试入口代码
[java] view plaincopy
//自身不会开启事务,在事务范围内则使用相同事务,否则不使用事务
@Test
public void testSupport(){
sService.addStudent6();
}
Service代码
[java] view plaincopy
@Transactional(propagation = Propagation.SUPPORTS)
public void addStudent6(){
String sql = "insert into student(name) values('st6')";
jdbcTemplate.execute(sql);
tService.addTeacher6();
throw new RuntimeException();
}
[java] view plaincopy
@Transactional(propagation = Propagation.SUPPORTS)
public void addTeacher6(){
String sql = "insert into teacher(name) values ('t6')";
jdbcTemplate.execute(sql);
}
经测试如果在addStudent6中抛出异常,学生数据和教师数据都被正确提交。说明sService和tService没有被spring管理和开启事务,而是使用了本地事务,由于本地事务默认自动提交因此数据都提交成功,但它们使用的却不是同一个事务,一旦出现异常将导致数据的不一致。
Propagation.NOT_SUPPORTED
测试入口代码
[java] view plaincopy
//自身不会开启事务,在事务范围内使用挂起事务,运行完毕恢复事务
@Test
public void testNotSupport(){
sService.addStudent4();
}
Service代码
[java] view plaincopy
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void addStudent4(){
String sql = "insert into student(name) values('st4')";
jdbcTemplate.execute(sql);
throw new RuntimeException();
}
经测试如果在addStudent4中抛出异常,学生数据正确提交。说明sService没有被spring管理和开启事务,而是使用了本地事务,由于本地事务默认自动提交因此数据都提交成功。
测试入口代码
[java] view plaincopy
//自身不会开启事务,在事务范围内使用挂起事务,运行完毕恢复事务
@Test
public void testNotSupport1(){
sService.addStudent();
}
Service代码
[java] view plaincopy
@Transactional(propagation = Propagation.REQUIRED)
public void addStudent(){
String sql = "insert into student(name) values('st0')";
jdbcTemplate.execute(sql);
tService.addTeacher4();
}
[java] view plaincopy
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void addTeacher4(){
String sql = "insert into teacher(name) values ('t4')";
jdbcTemplate.execute(sql);
throw new RuntimeException();
}
经测试如果在addTeacher4中抛出异常,学生数据提交失败,教师数据提交成功。说明sService开启了事务,tService没有开启事务,而是使用了本地事务。
Propagation.MANDATORY
测试入口代码
[java] view plaincopy
//自身不开启事务,必须在事务环境使用否则报错
@Test
public void testMandatory(){
sService.addStudent1();
}
Service代码
[java] view plaincopy
@Transactional(propagation = Propagation.MANDATORY)
public void addStudent1(){
String sql = "insert into student(name) values('st1')";
jdbcTemplate.execute(sql);
}
经测试代码报错。
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory',没有找到事务环境。
Propagation.NEVER
测试入口代码
[java] view plaincopy
<span style="font-size:14px">//自身不会开启事务,在事务范围使用抛出异常
@Test
public void testNever(){
sService.addStudent();
}</span>
Service代码
[java] view plaincopy
<span style="font-size:14px">@Transactional(propagation = Propagation.REQUIRED)
public void addStudent(){
String sql = "insert into student(name) values('st0')";
jdbcTemplate.execute(sql);
tService.addTeacher3();
}</span>
[java] view plaincopy
<span style="font-size:14px">@Transactional(propagation = Propagation.NEVER)
public void addTeacher3(){
String sql = "insert into teacher(name) values ('t3')";
jdbcTemplate.execute(sql);
}</span><span style="font-size:18px">
</span>
经测试代码报错,由于sService开启了事务,当调用sService方法时由于其传播特性为never,因此报存在事务错误。
org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'
Propagation.NESTED
测试入口代码
[java] view plaincopy
//如果没有事务环境其特性同Propagation.REQUIRED,否则嵌套运行事务
@Test
public void testNested(){
sService.addStudent2();
}
Service代码
[java] view plaincopy
@Transactional(propagation = Propagation.NESTED)
public void addStudent2(){
String sql = "insert into student(name) values('st2')";
jdbcTemplate.execute(sql);
tService.addTeacher2();
throw new RuntimeException();
}
[java] view plaincopy
@Transactional(propagation = Propagation.NESTED)
public void addTeacher2(){
String sql = "insert into teacher(name) values ('t2')";
jdbcTemplate.execute(sql);
}
经测试代码报错,教师数据和学生数据都没有提交成功。说明其按照REQUIRED特性运行。对于嵌套事务,大家可以模拟两个数据源,一方的失败不会影响另一方。
以上是所有demo解析。完整的测试代码请在:Spring事务传播特性下载。
另:
大家感兴趣SpringAOP入门和原理,可以在SpringAOP下载。
分享到:
相关推荐
总结来说,"Spring事务传播Demo"是一个用于学习和演示Spring事务管理和传播行为的实例,通过分析和实践这个Demo,开发者可以更好地理解和掌握Spring在处理事务时的复杂情况,提升在实际项目中的应用能力。...
7. **案例分析**:"SPRING事务管理案例分析.docx"很可能包含了具体的项目实例,详细讲解了如何在Spring项目中配置和使用事务管理,以及如何解决实践中遇到的问题。而"studyspring"可能是源代码目录,包含了实现这些...
在本课程中,我们将深入探讨Spring事务传播原理和数据库事务操作的基本概念,这对于有Spring开发经验的人员来说,是进一步深化事务控制理解的关键。我们还将触及分布式事务的初步知识,帮助开发者更好地掌握基于...
### Spring事务管理详解 #### 一、Spring事务管理概述 Spring框架提供了强大的事务管理功能,使得开发者能够更方便地管理应用程序中的事务。Spring事务管理主要包括两种类型:编程式事务管理和声明式事务管理。 -...
2. 事务传播行为:这决定了在一个事务内如何调用另一个事务性方法。例如,`PROPAGATION_REQUIRED` 表示如果当前存在事务,则加入到当前事务中;如果不存在,则新建一个事务。其他的传播行为还有 `PROPAGATION_...
Spring 源代码分析系列涵盖了多个关键模块,包括事务处理、IoC容器、JDBC、MVC、AOP以及与Hibernate和Acegi安全框架的集成。以下是对这些知识点的详细阐述: 1. **Spring 事务处理**:Spring 提供了声明式事务管理...
本篇文章将深入探讨Spring中的事务管理机制,通过实例分析事务的基本概念、特性以及如何在Spring中实现事务管理。 首先,事务是数据库操作的核心概念,它是一个逻辑工作单元,包含了多个数据库操作。事务具有四大...
在Spring框架中,`@Transactional`注解是用于标记事务管理的重要工具,它使得开发者能够方便地在代码中声明式地控制事务的...通过实例分析和源码阅读,我们可以更深入地理解Spring事务管理机制,提升我们的编程技能。
`Spring事务传播特性`是Spring框架提供的一种机制,它定义了在一个事务方法被另一个事务方法调用时,应该如何处理事务的边界。了解这一特性对于编写健壮的、事务性的Java应用至关重要。 首先,Spring事务传播行为...
本篇将深入探讨Spring事务传播行为,以及如何在实际应用中进行配置和使用。 1. **事务传播行为** Spring事务管理支持7种不同的事务传播行为,这些行为定义了一个事务方法在被另一个事务方法调用时应该如何处理: ...
面向切面编程(AOP)是Spring框架的核心特性之一,它允许开发者定义“切面”,这些切面可以包含业务逻辑的各个方面,如日志、安全检查、事务管理等。通过AOP,我们可以将这些关注点从主业务逻辑中解耦,提高代码的...
根据提供的文件信息,本文将详细解析Spring 1.2中声明式事务管理的相关知识点,包括其配置方式、工作原理以及如何在实际应用中实施。 ### Spring 1.2声明式事务简介 Spring框架中的声明式事务管理是通过AOP(面向...
包括`spring-context`、`spring-webmvc`、`spring-web`、`spring-beans`、`spring-core`、`spring-jdbc`、`spring-aop`、`spring-tx`、`spring-jms`以及`spring-expression`,通过源码解析,揭示其内部机制和设计...
《Spring源码深度解析》 在Java开发领域,Spring框架无疑是最重要的存在之一。它以其强大的功能、灵活的设计和丰富的生态,赢得了广大开发者们的青睐。深入理解Spring源码,不仅可以帮助我们更好地利用这个框架,还...
Spring的核心特性包括依赖注入(Dependency Injection, DI)、面向切面编程(Aspect-Oriented Programming, AOP)、资源管理、事务处理以及各种模块如数据访问、Web支持等。依赖注入是Spring的核心,它通过反转控制...
### Spring源码分析知识点 #### 一、Spring框架概述 Spring框架是一个全面的企业级应用开发框架,它通过一系列模块化的组件来支持不同的应用场景和技术需求。Spring的核心价值在于提供了一种简洁的方式来解决企业...
2. **Spring Context**:建立在核心容器基础上,添加了对国际化、事件传播、资源加载以及事务管理的支持。 3. **Spring AOP**:面向切面编程的支持,允许以声明的方式将切面加入到业务逻辑中。 4. **Spring DAO**:...
2. **Spring Context**:提供了BeanFactory的扩展,引入了国际化支持、事件传播机制、资源加载以及应用层配置等特性。 3. **Spring AOP**:面向切面编程的支持,允许定义方法拦截器和切入点,实现更灵活的代码组织。...