Spring事务机制主要包括声明式事务和编程式事务,此处侧重讲解声明式事务,编程式事务在实际开发中得不到广泛使用,仅供学习参考。

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

下面分别详细讲解,事务的四种属性,仅供诸位学习参考:

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

1
2
3
4
5
6
public interface TransactionDefinition {
int getPropagationBehavior();//返回事务的传播行为。
int getIsolationLevel();//返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据。
int getTimeout();//返回事务必须在多少秒内完成。
boolean isReadOnly();//事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的。
}

1. TransactionDefinition接口中定义五个隔离级别:

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

ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。

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

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

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

1: Dirty reads(脏读)。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。
2: non-repeatable reads(数据不可重复读)。比如事务A中两处读取数据-total-的值。在第一读的时候,total是100,然后事务B就把total的数据改成200,事务A再读一次,结果就发现,total竟然就变成200了,造成事务A数据混乱。
3: phantom reads(幻象读数据),这个和non-repeatable reads相似,也是同一个事务中多次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了(比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变,而是他的条件数据集改变。比如Select account.id where account.name=”ppgogo*”,第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由”dd”改成”ppgogo1″,结果取出来了7个数据。

2. 在TransactionDefinition接口中定义了七个事务传播行为:

(1)PROPAGATION_REQUIRED 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。

Java代码:

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

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

单独调用methodB方法:

Java代码

1
2
3
4
5
main{
metodB();
}

相当于

Java代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Main{
Connection con=null;
try{
con = getConnection();
con.setAutoCommit(false);
//方法调用
methodB();
//提交事务
con.commit();
}
Catch(RuntimeException ex){
            //回滚事务
con.rollback();  
}
finally{
//释放资源
closeCon();
}
}

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

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

执行效果相当于:

Java代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
         main{
Connection con = null;
try{
con = getConnection();
    methodA();
con.commit();
}
catch(RuntimeException ex){
con.rollback();
}
finally{
   closeCon();
}

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

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

Java代码:

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

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

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

Java代码:

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

当单独调用methodB时,因为当前没有一个活动的事务,则会抛出异常throw new IllegalTransactionStateException(“Transaction propagation ‘mandatory’ but no existing transaction found”);当调用methodA时,methodB则加入到methodA的事务中,事务地执行。

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

Java代码:

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

Java代码:

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

相当于

Java代码:

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

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

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

(7)PROPAGATION_NESTED如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。这是一个嵌套事务,使用JDBC 3.0驱动时,仅仅支持DataSourceTransactionManager作为事务管理器。需要JDBC 驱动的java.sql.Savepoint类。有一些JTA的事务管理器实现可能也提供了同样的功能。使用PROPAGATION_NESTED,还需要把PlatformTransactionManager的nestedTransactionAllowed属性设为true;而nestedTransactionAllowed属性值默认为false;

Java代码:

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

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

Java代码:

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

当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_REQUIRES_NEW 启动一个新的, 不依赖于环境的 “内部” 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行。

另一方面, PROPAGATION_NESTED 开始一个 “嵌套的” 事务,  它是已经存在事务的一个真正的子事务. 潜套事务开始执行时,  它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。

由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back.
PROPAGATION_REQUIRED应该是我们首先的事务传播行为。它能够满足我们大多数的事务需求。

from: https://my.oschina.net/xianggao/blog/84237?fromerr=ReFPLSuv

http://www.cnblogs.com/csniper/p/5536633.html

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,是一个Java开源框架,是为了解决企业应用程序开发复杂性由Rod Johnson创建的.框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序 ...

  4. Spring事务管理详解

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

  5. Spring 事务使用详解

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

  6. Spring事务原理详解

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

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

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

  8. 多数据源 事务管理_可能是最漂亮的Spring事务管理详解

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

  9. Spring事件机制详解

    一.前言 说来惭愧,对应Spring事件机制之前只知道实现 ApplicationListener 接口,就可以基于Spring自带的事件做一些事情(如ContextRefreshedEvent),但 ...

最新文章

  1. u盘循环冗余能修复吗_古董修复能修复吗?-恩平 - 商业服务
  2. RDKit | 基于RDKit的指定原子或键高亮
  3. Python 机器学习之项目实践
  4. mac中使用 sourcetree 的快速配置和git服务器登录
  5. 存储库访问被拒绝。通过部署密钥进行访问是只读的
  6. 什么是Linux的原生GUI API?
  7. 从ADAS到无人驾驶 关键技术有哪些
  8. 利用curl命令测试服务端
  9. 初学 Ajax(涉及 php)
  10. [react] 浏览器为什么无法直接JSX?怎么解决呢?
  11. jvm详解、GC、堆内存参数调优
  12. H3C服务器系统配置ip,H3C交换机DHCP 服务器动态分配地址典型配置指导
  13. Java学习(1)——用显式转换显式字符在Unicode表中的位置
  14. ansys16.0安装教程
  15. Win7 XP双系统安装
  16. [CVPR2022|基于文本实例分割]ReSTR: Convolution-free Referring Image Segmentation Using Transformers
  17. 腾讯加盟:Kafka-on-Pulsar 项目迎来 2 位腾讯 Maintainer!
  18. php融云开发文档,融云应用公众服务开发者文档 - 融云 RongCloud
  19. 尤雨溪: 2022 Web 前端生态趋势
  20. FTP/SFTP客户端:Transmit Mac中文版

热门文章

  1. 使用 Java 配置进行 Spring bean 管理--转
  2. 【聚类算法】常见的六大聚类算法
  3. 【项目管理】敏捷开发项目管理流程
  4. 【Xmind】,让你的大脑解放出来
  5. 这么多年,终于有人讲清楚 Transformer 了!
  6. 区块链研习 | 区块链里所说的“智能合约”是什么? 本文作者:敖萌 编辑:温晓桦 2017-10-11 20:31 导语:谈到区块链,必然离不开“智能合约”这个词。我们在本系列的第一篇文章中提到“智能
  7. 德意志银行CEO:将逐渐用 AI 替代人工,银行决不会一成不变 凤凰科技 09-08 20:41 原标题:德意志银行CEO:将逐渐用 AI 替代人工,银行决不会一成不变 雷锋网AI金融评论报道,外媒i
  8. Spring Boot - 自动配置实现原理
  9. Spring Boot2.x-15 整合RabbitMQ 及RabbitMQ的基本使用
  10. Imageloader3-单例模式