深入理解Spring事务原理

一、事务的基本原理
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:
 1.获取连接 Connection con = DriverManager.getConnection()
 2.开启事务con.setAutoCommit(true/false);
 3.执行CRUD
 4.提交事务/回滚事务 con.commit() / con.rollback();
 5.关闭连接 conn.close();

使用Spring的事务管理功能后,我们可以不再写步骤 2 和 4 的代码,而是由Spirng 自动完成。
那么Spring是如何在我们书写的 CRUD 之前和之后开启事务和关闭事务的呢?解决这个问题,也就可以从整体上理解Spring的事务管理实现原理了。下面简单地介绍下,注解方式为例子
 1.配置文件开启注解驱动,在相关的类和方法上通过注解@Transactional标识。
 2.spring 在启动的时候会去解析生成相关的bean,这时候会查看拥有相关注解的类和方法,并且为这些类和方法生成代理,并根据@Transaction的相关参数进行相关配置注入,这样就在代理中为我们把相关的事务处理掉了(开启正常提交事务,异常回滚事务)。
 3.真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

二、Spring 事务的传播属性
所谓spring事务的传播属性,就是定义在存在多个事务同时存在的时候,spring应该如何处理这些事务的行为。这些属性在TransactionDefinition中定义,具体常量的解释见下表:

三、数据库隔离级别

脏读:一事务对数据进行了增删改,但未提交,另一事务可以读取到未提交的数据。如果第一个事务这时候回滚了,那么第二个事务就读到了脏数据。
不可重复读:一个事务中发生了两次读操作,第一次读操作和第二次操作之间,另外一个事务对数据进行了修改,这时候两次读取的数据是不一致的。
幻读:第一个事务对一定范围的数据进行批量修改,第二个事务在这个范围增加一条数据,这时候第一个事务就会丢失对新增数据的修改。
总结
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。 
大多数的数据库默认隔离级别为 Read Commited,比如 SqlServer、Oracle
少数数据库默认隔离级别为:Repeatable Read 比如: MySQL InnoDB

四、Spring中的隔离级别

五、事务的嵌套
通过上面的理论知识的铺垫,我们大致知道了数据库事务和spring事务的一些属性和特点,接下来我们通过分析一些嵌套事务的场景,来深入理解spring事务传播的机制。
假设外层事务 Service A 的 Method A() 调用 内层Service B 的 Method B()
PROPAGATION_REQUIRED(spring 默认)
如果ServiceB.methodB() 的事务级别定义为 PROPAGATION_REQUIRED,那么执行 ServiceA.methodA() 的时候spring已经起了事务,这时调用 ServiceB.methodB(),ServiceB.methodB() 看到自己已经运行在 ServiceA.methodA() 的事务内部,就不再起新的事务。
假如 ServiceB.methodB() 运行的时候发现自己没有在事务中,他就会为自己分配一个事务。
这样,在 ServiceA.methodA() 或者在 ServiceB.methodB() 内的任何地方出现异常,事务都会被回滚。
PROPAGATION_REQUIRES_NEW
比如我们设计 ServiceA.methodA() 的事务级别为 PROPAGATION_REQUIRED,ServiceB.methodB() 的事务级别为 PROPAGATION_REQUIRES_NEW。
那么当执行到 ServiceB.methodB() 的时候,ServiceA.methodA() 所在的事务就会挂起,ServiceB.methodB() 会起一个新的事务,等待 ServiceB.methodB() 的事务完成以后,它才继续执行。
他与 PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为 ServiceB.methodB() 是新起一个事务,那么就是存在两个不同的事务。如果 ServiceB.methodB() 已经提交,那么 ServiceA.methodA() 失败回滚,ServiceB.methodB() 是不会回滚的。如果 ServiceB.methodB() 失败回滚,如果他抛出的异常被 ServiceA.methodA() 捕获,ServiceA.methodA() 事务仍然可能提交(主要看B抛出的异常是不是A会回滚的异常)。
PROPAGATION_SUPPORTS
假设ServiceB.methodB() 的事务级别为 PROPAGATION_SUPPORTS,那么当执行到ServiceB.methodB()时,如果发现ServiceA.methodA()已经开启了一个事务,则加入当前的事务,如果发现ServiceA.methodA()没有开启事务,则自己也不开启事务。这种时候,内部方法的事务性完全依赖于最外层的事务。
PROPAGATION_NESTED
现在的情况就变得比较复杂了, ServiceB.methodB() 的事务属性被配置为 PROPAGATION_NESTED, 此时两者之间又将如何协作呢? 
ServiceB#methodB 如果 rollback, 那么内部事务(即 ServiceB#methodB) 将回滚到它执行前的 SavePoint 而外部事务(即 ServiceA#methodA) 可以有以下两种处理方式:

a、捕获异常,执行异常分支逻辑

 void methodA() { 

  try { 

   ServiceB.methodB(); 

  } catch (SomeException) { 

   // 执行其他业务, 如 ServiceC.methodC(); 

  } 

 }

这种方式也是嵌套事务最有价值的地方, 它起到了分支执行的效果, 如果 ServiceB.methodB 失败, 那么执行 ServiceC.methodC(), 而 ServiceB.methodB 已经回滚到它执行之前的 SavePoint, 所以不会产生脏数据(相当于此方法从未执行过), 这种特性可以用在某些特殊的业务中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都没有办法做到这一点。
b、外部事务回滚/提交 代码不做任何修改, 那么如果内部事务(ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滚到它执行之前的 SavePoint(在任何情况下都会如此), 外部事务(即 ServiceA#methodA) 将根据具体的配置决定自己是 commit 还是 rollback
另外三种事务传播属性基本用不到,在此不做分析。

六、总结
对于项目中需要使用到事务的地方,我建议开发者还是使用spring的TransactionCallback接口来实现事务,不要盲目使用spring事务注解,如果一定要使用注解,那么一定要对spring事务的传播机制和隔离级别有个详细的了解,否则很可能发生意想不到的效果。

(0)

相关推荐

  • 浅谈SSH框架中spring的原理

    在ssh项目中,是有明确分工的,spring的作用就相当于将struts和hibernate连接起来,是将两个没有关系的框架的特性,方法,action都放在spring的配置文件中使他们建立关系.取他门各自所长.而这些做法他们自己不知道,他们是听命于spring调度的,他的的任务只是做好自己的事情. 这样做的好处就是任务结构分明,struts只管理显示与做什么,hibernate只关心怎么做,而spring就相当于领导,所以一切的类都要交给spring的工厂创建,这是一种良好的开发模式,体现了一

  • Spring AOP的实现原理详解及实例

    Spring AOP的实现原理详解及实例 spring 实现AOP是依赖JDK动态代理和CGLIB代理实现的. 以下是JDK动态代理和CGLIB代理简单介绍 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理. CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类.CGLIB是高效的代码生成包,底层是依靠ASM(开源的Java字节码编辑类库)操作字节码实现的,性能比JDK强. 在Spring中

  • 详解JSP 中Spring工作原理及其作用

    详解JSP 中Spring工作原理及其作用 1.springmvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作. 2.DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller. 3.DispatcherServlet请请求提交到目标Controller 4.Controller进行业务逻辑处理后,会返回一个ModelAndView 5.Dispathcher查询一个或多个

  • 全面解析SpringBoot自动配置的实现原理

    之前一直在用SpringBoot框架,一直感觉SpringBoot框架自动配置的功能很强大,但是并没有明白它是怎么实现自动配置的,现在有空研究了一下,大概明白了SpringBoot框架是怎么实现自动配置的功能,我们编写一个最简单的自动配置功能,大概的总结一下. 一,配置属性类 其实就是值对象注入的方式去配置一些Spring常用的配置,我们编写一个最简单的配置对象. @ConfigurationProperties(prefix = "hello") //@Component //如果这

  • 深入浅析Spring 的aop实现原理

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系.例如日志功能.日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无

  • Spring mvc工作原理_动力节点Java学院整理

    SpringMVC框架介绍 Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块.使用 Spring 可插入的 MVC 架构,可以选择是使用内置的 Spring Web 框架还是 Struts 这样的 Web 框架.通过策略接口,Spring 框架是高度可配置的,而且包含多种视图技术,例如 JavaServer Pages(JSP)技术.Velocity.Tiles

  • spring boot启动加载数据原理分析

    实际应用中,我们会有在项目服务启动的时候就去加载一些数据或做一些事情这样的需求. 为了解决这样的问题,spring Boot 为我们提供了一个方法,通过实现接口 CommandLineRunner 来实现. 创建实现接口 CommandLineRunner 的类,通过@Component注解,就可以实现启动时加载数据项.使用@Order 注解来定义执行顺序. IndexStartupRunner.Java类: import org.springframework.boot.CommandLine

  • 深入理解Spring事务原理

    一.事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的.对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:  1.获取连接 Connection con = DriverManager.getConnection()  2.开启事务con.setAutoCommit(true/false);  3.执行CRUD  4.提交事务/回滚事务 con.commit() / con.rollback();  5.关闭连接

  • Spring事务原理解析

    目录 前言 问题描述 代码复现 排查 1. 锁失效 2. 事务隔离级别 3. 修改Spring事务传播配置 解决方案 前言 最近在编写公司APP产品的商品砍价功能,其中有一个接口涉及并发访问.自测时通过ApiFox接口管理工具进行压测,落地数据时出现了"锁失效"的情景.十分感谢后端小伙伴的帮助排查,解决了这个问题. 问题描述 并发接口中,先对主表数据进行读取,进行业务判断后,新增.修改它表的数据.在理应串行执行的情况下发生了多个请求线程读取到了相同的主表数据,导致数据处理异常.也正是前

  • 深入理解spring事务

    事务介绍 一个事务要么同时成功,要么同时失败 特性 Atomic原子性 事务是由一个或多个活动组成的一个工作单元.原子性确保事务中的所有操作全部发生或全部不发生 Consistent一致性 一旦事务完成,系统必须确保它所建模的业务处于一致的状态 Isolated隔离性 事务允许多个用户对数据进行操作,每个用户的操作不会与其他用户纠缠在一起 Durable持久性 一旦事务完成,事务的结果应该持久化 事务隔离级别 DEFAULT 使用底层数据库预设的隔离层级 READ_UNCOMMITTED (读未

  • 深入理解Spring事务的传播行为

    前言 本文主要介绍下Spring事务中的传播行为.事务传播行为是Spring框架独有的事务增强特性,他不属于的事务实际提供方数据库行为.这是Spring为我们提供的强大的工具箱,使用事务传播行可以为我们的开发工作提供许多便利. 下面话不多说了,来一起看看详细的介绍吧 事务传播行为介绍 Spring中的7个事务传播行为: |事务行为|说明 | |:--|:--| |PROPAGATION_REQUIRED | 支持当前事务,假设当前没有事务.就新建一个事务 | | PROPAGATION_SUPP

  • 这一次搞懂Spring事务注解的解析方式

    前言 事务我们都知道是什么,而Spring事务就是在数据库之上利用AOP提供声明式事务和编程式事务帮助我们简化开发,解耦业务逻辑和系统逻辑.但是Spring事务原理是怎样?事务在方法间是如何传播的?为什么有时候事务会失效?接下来几篇文章将重点分析Spring事务源码,让我们彻底搞懂Spring事务的原理. 正文 XML标签的解析 <tx:annotation-driven transaction-manager="transactionManager"/> 配置过事务的应该

  • 8个Spring事务失效场景详解

    目录 前言 Spring事务原理 Spring事务失效场景 1. 抛出检查异常 2. 业务方法本身捕获了异常 3. 同一类中的方法调用 4. 方法使用 final 或 static关键字 5. 方法不是public 6. 错误使用传播机制 7. 没有被Spring管理 8. 多线程 总结 前言 作为Java开发工程师,相信大家对Spring种事务的使用并不陌生.但是你可能只是停留在基础的使用层面上,在遇到一些比较特殊的场景,事务可能没有生效,直接在生产上暴露了,这可能就会导致比较严重的生产事故.

  • spring事务Propagation及其实现原理详解

    本文研究的主要是spring事务Propagation及其实现原理,具体介绍如下. 简介 spring目前已是java开发的一个事实标准,这得益于它的便利.功能齐全.容易上手等特性.在开发过程当中,操作DB是非常常见的操作,而涉及到db,就会涉及到事务.事务在平时的开发过程当中,就算没有注意到,程序正常执行不会有副作用,但如果出现了异常,而又没有处理好事务的话,可能就会出现意想不到的结果.spring在事务方面进行了各种操作的封装,特别是声明式事务的出现,让开发变得更加的舒心.spring对事务

  • Spring事务管理原理及方法详解

    这篇文章主要介绍了Spring事务管理原理及方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 事务,在日常开发或者面试中都必定会涉及到.开发工作中,结合数据库开发理解就是:一组dml要么全部成功执行提交,要么因为某一个操作异常,撤销之前所做的成功的操作,整体执行失败.再简单点的一句话:生死与共. 由此,可以看出,事务的必要性:在开发工作中,保证操作数据的安全性.事务的控制也就是保证数据的访问安全性. 一.事务的四大特性 A:原子性(ato

  • Spring事务annotation原理详解

    这篇文章主要介绍了Spring事务annotation原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在使用Spring的时候,配置文件中我们经常看到 annotation-driven 这样的注解,其含义就是支持注解,一般根据前缀 tx.mvc 等也能很直白的理解出来分别的作用. <tx:annotation-driven/> 就是支持事务注解的(@Transactional) . <mvc:annotation-driven

  • Spring底层事务原理解析

    目录 一.@EnableTransactionManagement工作原理 二.Spring事务基本执行原理 四.Spring事务传播机制 五.Spring事务传播机制分类 六.Spring事务强制回滚 七.TransactionSynchronization 一.@EnableTransactionManagement工作原理 开启Spring事务本质上就是增加了一个Advisor,但我们使用 @EnableTransactionManagement注解来开启Spring事务是,该注解代理的功

随机推荐