spring,是一个Java开源框架,是为了解决企业应用程序开发复杂性由Rod Johnson创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。

Spring声明式事务让我们从复杂的事务处理中得到解脱,使得我们再也不必去处理获得连接、关闭连接、事务提交和回滚等这些操作,再也无需我们在与事务相关的方法中处理大量的try…catch…finally代码。 
我们在使用Spring声明式事务时,有一个非常重要的概念就是事务属性。事务属性通常由事务的传播行为、事务的隔离级别、事务的超时值、事务只读标志组成。我们在进行事务划分时,需要进行事务定义,也就是配置事务的属性。

Spring在TransactionDefinition接口中定义这些属性,以供PlatfromTransactionManager(github)使用,PlatfromTransactionManager是spring事务管理的核心接口。

TransactionDefinition.java(spring-tx/src/main/java/org/springframework/transaction/TransactionDefinition.java,github)

[java] view plaincopy print?
  1. public interface TransactionDefinition {
  2. int getPropagationBehavior();
  3. int getIsolationLevel();
  4. int getTimeout();
  5. boolean isReadOnly();
  6. }

1) getPropagationBehavior(): 返回事务的传播行为,由是否有一个活动的事务来决定一个事务调用。 
2) getTimeout(): 它返回事务必须在多少秒内完成。 
3) isReadOnly(): 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的。 
4) getIsolationLevel(): 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据。

在TransactionDefinition接口中,定义了五个不同的事务隔离级别 :
1) ISOLATION_DEFAULT 

这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应

2) ISOLATION_READ_UNCOMMITTED 

这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。 
  例如: 
  Mary的原工资为1000,财务人员将Mary的工资改为了8000,但未提交事务

  1. Connection con1 = getConnection();
  2. con.setAutoCommit(false);
  3. update employee set salary = 8000 where empId ="Mary";

与此同时,Mary正在读取自己的工资

  1. Connection con2 = getConnection();
  2. select  salary from employee where empId ="Mary";
  3. con2.commit();

Mary发现自己的工资变为了8000,欢天喜地! 
而财务发现操作有误,而回滚了事务,Mary的工资又变为了1000

  1. //con1
  2. con1.rollback();

像这样,Mary记取的工资数8000是一个脏数据。 
ISOLATION_READ_COMMITTED  保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。

ISOLATION_REPEATABLE_READ  这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。

在事务1中,Mary 读取了自己的工资为1000,操作并没有完成

  1. con1 = getConnection();
  2. select salary from employee empId ="Mary";

在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务.

  1. con2 = getConnection();
  2. update employee set salary = 2000;
  3. con2.commit();

在事务1中,Mary 再次读取自己的工资时,工资变为了2000

  1. //con1
  2. select salary from employee empId ="Mary";

在一个事务中前后两次读取的结果并不致,导致了不可重复读。 
使用ISOLATION_REPEATABLE_READ可以避免这种情况发生。

ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。

目前工资为1000的员工有10人。 
事务1,读取所有工资为1000的员工。

  1. con1 = getConnection();
  2. Select * from employee where salary =1000;

共读取10条记录

这时另一个事务向employee表插入了一条员工记录,工资也为1000

  1. con2 = getConnection();
  2. Insert into employee(empId,salary) values("Lili",1000);
  3. con2.commit();

事务1再次读取所有工资为1000的员工

  1. //con1
  2. select * from employee where salary =1000;

共读取到了11条记录,这就产生了幻像读。 
ISOLATION_SERIALIZABLE能避免这样的情况发生。但是这样也耗费了最大的资源。

getPropagationBehavior()返回事务的传播行为,由是否有一个活动的事务来决定一个事务调用。 
在TransactionDefinition接口中定义了七个事务传播行为。 
PROPAGATION_REQUIRED 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。

  1. //事务属性 PROPAGATION_REQUIRED
  2. methodA{
  3. ……
  4. methodB();
  5. ……
  6. }
  7. //事务属性 PROPAGATION_REQUIRED
  8. methodB{
  9. ……
  10. }

使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务。

单独调用methodB方法

  1. main{
  2. metodB();
  3. }

相当于

  1. Main{
  2. Connection con=null;
  3. rry{
  4. con = getConnection();
  5. con.setAutoCommit(false);
  6. //方法调用
  7. methodB();
  8. //提交事务
  9. con.commit();
  10. }
  11. Catch(RuntimeException ex){
  12. //回滚事务
  13. con.rollback();
  14. }
  15. finally{
  16. //释放资源
  17. closeCon();
  18. }
  19. }

Spring保证在methodB方法中所有的调用都获得到一个相同的连接。在调用methodB时,没有一个存在的事务,所以获得一个新的连接,开启了一个新的事务。

单独调用MethodA时,在MethodA内又会调用MethodB.

执行效果相当于

  1. main{
  2. Connection con = null;
  3. try{
  4. con = getConnection();
  5. methodA();
  6. con.commit();
  7. }
  8. cathc(RuntimeException ex){
  9. con.rollback();
  10. }
  11. finally{
  12. closeCon();
  13. }
  14. }

调用MethodA时,环境中没有事务,所以开启一个新的事务. 
当在MethodA中调用MethodB时,环境中已经有了一个事务,所以methodB就加入当前事务。

PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。

  1. //事务属性 PROPAGATION_REQUIRED
  2. methodA(){
  3. methodB();
  4. }
  5. //事务属性 PROPAGATION_SUPPORTS
  6. methodB(){
  7. ……
  8. }

单纯的调用methodB时,methodB方法是非事务的执行的。 
当调用methdA时,methodB则加入了methodA的事务中,事务地执行。

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

  1. //事务属性 PROPAGATION_REQUIRED
  2. methodA(){
  3. methodB();
  4. }
  5. //事务属性 PROPAGATION_MANDATORY
  6. methodB(){
  7. ……
  8. }

当单独调用methodB时,因为当前没有一个活动的事务,则会抛出异常 
throw new IllegalTransactionStateException("Transaction propagation 'mandatory' but no existing transaction found");

当调用methodA时,methodB则加入到methodA的事务中,事务地执行。

PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。

  1. //事务属性 PROPAGATION_REQUIRED
  2. methodA(){
  3. doSomeThingA();
  4. methodB();
  5. doSomeThingB();
  6. }
  7. //事务属性 PROPAGATION_REQUIRES_NEW
  8. methodB(){
  9. ……
  10. }

当单独调用methodB时,相当于把methodb声明为REQUIRED。开启一个新的事务,事务地执行。

当调用methodA时

  1. main(){
  2. methodA();
  3. }

情况有些大不一样.相当于下面的效果。

  1. main(){
  2. TransactionManager tm = null;
  3. try{
  4. //获得一个JTA事务管理器
  5. tm = getTransactionManager();
  6. tm.begin();//开启一个新的事务
  7. Transaction ts1 = tm.getTransaction();
  8. doSomeThing();
  9. tm.suspend();//挂起当前事务
  10. try{
  11. tm.begin();//重新开启第二个事务
  12. Transaction ts2 = tm.getTransaction();
  13. methodB();
  14. ts2.commit();//提交第二个事务
  15. }
  16. Catch(RunTimeException ex){
  17. ts2.rollback();//回滚第二个事务
  18. }
  19. finally{
  20. //释放资源
  21. }
  22. //methodB执行完后,复恢第一个事务
  23. tm.resume(ts1);
  24. doSomeThingB();
  25. ts1.commit();//提交第一个事务
  26. }
  27. catch(RunTimeException ex){
  28. ts1.rollback();//回滚第一个事务
  29. }
  30. finally{
  31. //释放资源
  32. }
  33. }

在这里,我把ts1称为外层事务,ts2称为内层事务。从上面的代码可以看出,ts2与ts1是两个独立的事务,互不相干。Ts2是否成功并不依赖于ts1。如果methodA方法在调用methodB方法后的doSomeThingB方法失败了,而methodB方法所做的结果依然被提交。而除了methodB之外的其它代码导致的结果却被回滚了。 
使用PROPAGATION_REQUIRES_NEW,需要使用JtaTransactionManager作为事务管理器。

PROPAGATION_NOT_SUPPORTED  总是非事务地执行,并挂起任何存在的事务。

  1. //事务属性 PROPAGATION_REQUIRED
  2. methodA(){
  3. doSomeThingA();
  4. methodB();
  5. doSomeThingB();
  6. }
  7. //事务属性 PROPAGATION_NOT_SUPPORTED
  8. methodB(){
  9. ……
  10. }

当单独调用methodB时,不启用任何事务机制,非事务地执行。 
当调用methodA时,相当于下面的效果

  1. main(){
  2. TransactionManager tm = null;
  3. try{
  4. //获得一个JTA事务管理器
  5. tm = getTransactionManager();
  6. tm.begin();//开启一个新的事务
  7. Transaction ts1 = tm.getTransaction();
  8. doSomeThing();
  9. tm.suspend();//挂起当前事务
  10. methodB();
  11. //methodB执行完后,复恢第一个事务
  12. tm.resume(ts1);
  13. doSomeThingB();
  14. ts1.commit();//提交第一个事务
  15. }
  16. catch(RunTimeException ex){
  17. ts1.rollback();//回滚第一个事务
  18. }
  19. finally{
  20. //释放资源
  21. }
  22. }

使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作为事务管理器。

PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常

  1. //事务属性 PROPAGATION_REQUIRED
  2. methodA(){
  3. doSomeThingA();
  4. methodB();
  5. doSomeThingB();
  6. }
  7. //事务属性 PROPAGATION_NEVER
  8. methodB(){
  9. ……
  10. }

单独调用methodB,则非事务的执行。 
调用methodA则会抛出异常 
throw new IllegalTransactionStateException( 
"Transaction propagation 'never' but existing transaction found");

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

这是一个嵌套事务,使用JDBC 3.0驱动时,仅仅支持DataSourceTransactionManager作为事务管理器。需要JDBC 驱动的java.sql.Savepoint类。有一些JTA的事务管理器实现可能也提供了同样的功能。

使用PROPAGATION_NESTED,还需要把PlatformTransactionManager的nestedTransactionAllowed属性设为true; 
而nestedTransactionAllowed属性值默认为false;

  1. //事务属性 PROPAGATION_REQUIRED
  2. methodA(){
  3. doSomeThingA();
  4. methodB();
  5. doSomeThingB();
  6. }
  7. //事务属性 PROPAGATION_NESTED
  8. methodB(){
  9. ……
  10. }

如果单独调用methodB方法,则按REQUIRED属性执行。 
如果调用methodA方法,相当于下面的效果

  1. main(){
  2. Connection con = null;
  3. Savepoint savepoint = null;
  4. try{
  5. con = getConnection();
  6. con.setAutoCommit(false);
  7. doSomeThingA();
  8. savepoint = con2.setSavepoint();
  9. try
  10. methodB();
  11. }catch(RuntimeException ex){
  12. con.rollback(savepoint);
  13. }
  14. finally{
  15. //释放资源
  16. }
  17. doSomeThingB();
  18. con.commit();
  19. }
  20. catch(RuntimeException ex){
  21. con.rollback();
  22. }
  23. finally{
  24. //释放资源
  25. }
  26. }

当methodB方法调用之前,调用setSavepoint方法,保存当前的状态到savepoint。如果methodB方法调用失败,则恢复到之前保存的状态。但是需要注意的是,这时的事务并没有进行提交,如果后续的代码(doSomeThingB()方法)调用失败,则回滚包括methodB方法的所有操作。

嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区别:它们非常类似,都像一个嵌套事务,如果不存在一个活动的事务,都会开启一个新的事务。使用PROPAGATION_REQUIRES_NEW时,内层事务与外层事务就像两个独立的事务一样,一旦内层事务进行了提交后,外层事务不能对其进行回滚。两个事务互不影响。两个事务不是一个真正的嵌套事务。同时它需要JTA事务管理器的支持。 
使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务。DataSourceTransactionManager使用savepoint支持PROPAGATION_NESTED时,需要JDBC 3.0以上驱动及1.4以上的JDK版本支持。其它的JTA TrasactionManager实现可能有不同的支持方式。

PROPAGATION_REQUIRED应该是我们首先的事务传播行为。它能够满足我们大多数的事务需求。

参考推荐:

解惑 spring 嵌套事务

详解spring事务属性

from: http://blog.csdn.net/ithomer/article/details/10111467

Spring事务属性详解相关推荐

  1. 关于事务管理的理解和Spring事务管理详解

    转载于:http://www.mamicode.com/info-detail-1248286.html 1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000 ...

  2. Spring事务管理详解_基本原理_事务管理方式

    Spring事务管理详解_基本原理_事务管理方式 1. 事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,使用JDBC的事务管理机制,就是利用java.sql.Connection对象 ...

  3. (九)Spring 事务开发、事务属性详解

    持久层 目录 事务回顾 Spring 控制事务的开发 Spring 中的事务属性(Transaction Attribute) 隔离属性(ISOLATION) 传播属性(PROPAGATION) 只读 ...

  4. 【Spring 持久层】Spring 事务开发、事务属性详解

    持久层 事务回顾 Spring 事务编程开发 Spring 中的事务属性(Transaction Attribute) 隔离属性(ISOLATION) 传播属性(PROPAGATION) 只读属性(r ...

  5. Spring 事务使用详解

    前言 什么是事务?根据 维基百科事务 介绍,数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成.简单来说,事务就是将一系列操作当成一个不可拆分的执行逻辑单 ...

  6. Spring事务管理详解

    什么是事务 事务是逻辑上的一组操作,要么都执行,要么都不执行. 需要注意的是:事务能否生效数据库引擎是否支持事务是关键.比如常用的 MySQL 数据库默认使用支持事务的 innodb引擎.但是,如果把 ...

  7. Spring事务原理详解

    一.使用 spring事务开启和使用比较简单,需要有数据源和事务管理器,然后在启动门面类上开启事务,在需要使用事务的地方添加注解就可以了,我们简单做一下回顾. 1.配置数据源 spring.datas ...

  8. 什么是事务的传播_这么漂亮的Spring事务管理详解,你不来看看?

    事务概念回顾 什么是事务? 事务是逻辑上的一组操作,要么都执行,要么都不执行. 事物的特性(ACID): 原子性: 事务是最小的执行单位,不允许分割.事务的原子性确保动作要么全部完成,要么完全不起作用 ...

  9. Spring 事务机制详解

    Spring事务机制主要包括声明式事务和编程式事务,此处侧重讲解声明式事务,编程式事务在实际开发中得不到广泛使用,仅供学习参考. Spring声明式事务让我们从复杂的事务处理中得到解脱.使得我们再也无 ...

最新文章

  1. 从事嵌入式开发需要掌握哪些知识?从事嵌入式软件开发的前景如何?
  2. const与#define的异同
  3. css中flex布局
  4. 抽象类、抽象方法与代码块
  5. Python换行符问题:\r\n还是\n?
  6. 第二章 DateTime工具类
  7. View Controller Programming Guide for iOS---(七)---Resizing the View Controller’s Views
  8. 转换文档参数_1分钟教会你将Excel转换成Word,简单高效,办公人士必备神技
  9. 编程语言对比 主程序传参
  10. java中线程总结,JAVA中线程的相关小结
  11. linux232转usb接口驱动程序,USB转RS232串口驱动程序下载
  12. 第10章第13节:使用iSlide的图标库往幻灯片中插入一枚图标 [PowerPoint精美幻灯片实战教程]
  13. 没有项目经验,如何书写漂亮的简历?
  14. 动态域名解析ipv6 群辉dnspod_群晖设置ipv6动态域名
  15. OpenTCS打造移动机器人交通管制系统(十)
  16. android获取wifi的SSID
  17. CODE大全告诉你java是否开始没落了
  18. python学习笔记之pyinstaller failed to execute script问题
  19. DTP,VTP,链路聚合
  20. “TED演讲”可视化(应统期末作业)(二)

热门文章

  1. LESSON 9.1 随机森林回归器的实现
  2. 关于Linux Kernel中的宏定义likely和unlikely
  3. JSP JavaBean
  4. Linux makefile中的= := ?=操作符
  5. 关于Ping的TTL的含义
  6. 深入理解分布式技术 - 分布式缓存实战_Hot Key 和Big Key的发现与治理
  7. 深入理解分布式技术 - 分布式缓存总结回顾
  8. 白话Elasticsearch06- 深度探秘搜索技术之手动控制全文检索结果的精准度
  9. CuteBot智能小车
  10. 复习笔记(三)——C++类和对象