一:基础知识介绍

1.1:事务四个特性:ACID

  • 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么全部失败。

  • 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。

  • 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。

  • 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。

1.2 隔离级别错误说明

  1. 脏读:并发事务之间一个事务读取了另一个事务还未提交的数据。

  2. 不可重复读:并发事务间一个事务多次读取,分别读取了另一个事务未提交和已经提交的数据,导致多次读取的数据状态不一致。

  3. 幻读:并发事务间一个事务读取了另一个事务已经提交的数据。与不可重复读的区别是不可重复读前后读取的是同一数据项,而幻读是一批数据。比如前后读取的数据数量不一致。

1.3 数据库四大隔离级别

  1. Serializable(串行化):可避免脏读、不可重复读、幻读的发生。

  2. Repeatable Read(可重复读):可避免脏读、不可重复读的发生。

  3. Read Committed(读已提交):可避免脏读的发生。

  4. Read unCommitted:(读未提交):最低级别,任何情况都会发生。

1.4 Spring隔离级别属性

  1. TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。

  2. TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。

  3. TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。

  4. TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。

  5. TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

1.5 Spring事务的传播行为

事务的第一个方面是传播行为(propagation behavior)。当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

Spring定义了七种传播行为:

  1. TransactionDefinition.PROPAGATION_REQUIRED:如果当前事务存在,则加入当前事务;如果不存在,则创建一个新的事务。一般默认此项。

  2. TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前事务存在,则挂起当前事务。

  3. TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事物;如果事务不存在,则以无事务方式执行。

  4. TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式执行,如果当前事务存在,则挂起当前事务。

  5. TransactionDefinition.PROPAGATION_NEVER:以非事务方式执行,如果存在事务,则抛出异常。

  6. TransactionDefinition.PROPAGATION_MANDATORY:表示该方法必须在事务中运行,如果当前存在事务,则加入当前事务;如果不存在,则抛出异常。

  7. TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个新的事务作为当前事务内嵌事务执行,嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果不存在,则取该值等价于TransactionDefinition.PROPAGATION_REQUIRED,即创建一个新的事务

此@Transactional注解来自org.springframework.transaction.annotation包,而不是javax.transaction。

1.6 Spring事务分类

  • 声明式事务:即为在配置文件中配置,无需程序员手动编程控制事务,也就是说数据库的事务的开启,提交都是框架帮助我们做好的

  • 编程式事务:是需要在方法中加入Spring的事务API  例如hibernate中的  beginTransaction() commit() rollback, 更加具有细粒度,但是同时也增加了代码的倾入性!

二:核心接口

Spring事务管理的实现有许多细节,如果对整个接口框架有个大体了解会非常有利于我们理解事务,下面通过讲解Spring的事务接口来了解Spring实现事务的具体策略。 
Spring事务管理涉及的接口的联系如下:

2.1 事务管理器

Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。 
Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。此接口的内容如下:

Public interface PlatformTransactionManager()...{ // 由TransactionDefinition得到TransactionStatus对象TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; // 提交Void commit(TransactionStatus status) throws TransactionException; // 回滚Void rollback(TransactionStatus status) throws TransactionException; }

从这里可知具体的具体的事务管理机制对Spring来说是透明的,它并不关心那些,那些是对应各个平台需要关心的,所以Spring事务管理的一个优点就是为不同的事务API提供一致的编程模型,如JTA、JDBC、Hibernate、JPA。下面分别介绍各个平台框架实现事务管理的机制。

2.1.1 JDBC事务

如果应用程序中直接使用JDBC来进行持久化,DataSourceTransactionManager会为你处理事务边界。为了使用DataSourceTransactionManager,你需要使用如下的XML将其装配到应用程序的上下文定义中:

"transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> bean>

实际上,DataSourceTransactionManager是通过调用java.sql.Connection来管理事务,而后者是通过DataSource获取到的。通过调用连接的commit()方法来提交事务,同样,事务失败则通过调用rollback()方法进行回滚。

2.1.2 Hibernate事务

如果应用程序的持久化是通过Hibernate实习的,那么你需要使用HibernateTransactionManager。对于Hibernate3,需要在Spring上下文定义中添加如下的声明:

"transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> bean>

sessionFactory属性需要装配一个Hibernate的session工厂,HibernateTransactionManager的实现细节是它将事务管理的职责委托给org.hibernate.Transaction对象,而后者是从Hibernate Session中获取到的。当事务成功完成时,HibernateTransactionManager将会调用Transaction对象的commit()方法,反之,将会调用rollback()方法。

2.1.3 Java持久化API事务(JPA)

Hibernate多年来一直是事实上的Java持久化标准,但是现在Java持久化API作为真正的Java持久化标准进入大家的视野。如果你计划使用JPA的话,那你需要使用Spring的JpaTransactionManager来处理事务。你需要在Spring中这样配置JpaTransactionManager:

"transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> bean>

JpaTransactionManager只需要装配一个JPA实体管理工厂(javax.persistence.EntityManagerFactory接口的任意实现)。JpaTransactionManager将与由工厂所产生的JPA EntityManager合作来构建事务。

2.1.4 Java原生API事务

如果你没有使用以上所述的事务管理,或者是跨越了多个事务管理源(比如两个或者是多个不同的数据源),你就需要使用JtaTransactionManager:

"transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManagerName" value="java:/TransactionManager" /> bean>

JtaTransactionManager将事务管理的责任委托给javax.transaction.UserTransaction和javax.transaction.TransactionManager对象,其中事务成功完成通过UserTransaction.commit()方法提交,事务失败通过UserTransaction.rollback()方法回滚。

2.2 基本事务属性的定义

上面讲到的事务管理器接口PlatformTransactionManager通过getTransaction(TransactionDefinition definition)方法来得到事务,这个方法里面的参数是TransactionDefinition类,这个类就定义了一些基本的事务属性。 
那么什么是事务属性呢?事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。事务属性包含了5个方面,如图所示:

而TransactionDefinition接口内容如下:

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

我们可以发现TransactionDefinition正好用来定义事务属性,下面详细介绍一下各个事务属性。

2.2.1 Spring 事务实现原理

在应用系统调用 事务声明 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据事务配置信息,这个代理对象决定该声明事务的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,利用抽象事务管理器 AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务。

Spring AOP 代理有 CglibAopProxy 和 JdkDynamicAopProxy 两种,以CglibAopProxy 为例,对于CglibAopProxy,需要调用其内部类的DynamicAdvisedInterceptor 的 intercept 方法。对于 JdkDynamicAopProxy,则调用其 invoke 方法。

三:遇到的问题

3.1:如果只是加了@Transactional注解,事务并不生效。

  • 事务注解是否开启:

xml:"transactionManager">java:@EnableTransactionManagement 开启事务支持后

这个注解若是加载方法上,只能加在public的方法上,加到其他如private上不会报错,但是事务控制就不会生效。

mysql数据库:myisam存储引擎不支持事务,换成innodb

3.2 Spring事务中需要注意的问题

事务失效问题

在同一个代理对象内部,事务方法之间的直接嵌套调用,普通方法和事务方法之间的直接嵌套调用,都会造成事务异常!具体表现为某些传播行为不生效或者直接事务控制不生效。

@Servicepublic class DemoService { 

@Transaction public void transactionMethod1()  { op1();op2(); ... } public void commonMethod(){  ...transactionMethod1(); //照顾基础不牢的朋友,这里相当于 this.transactionMethod1();  ...  } 

@Transaction public void transactionMethod2(){  ...this.transactionMethod3(); ... } 

@Transaction(propagation= Propagation.REQUIRES_NEW) public void transactionMethod3()  { op3(); ... } }

上面代码中,如果调用 DemoService 的 bean 对象的commonMethod ,则transactionMethod1里定义的事务将不生效(比如op2发生错误时,并不会回滚op1的操作),bean 调用 transactionMethod2时,transactionMethod2时里面调用的transactionMethod3也不会开启新的事务。

为什么会这样?

上面的实现机制中讲到,AOP的实现都是通过动态代理来实现,而AOP限制了我们只能在目标方法的开始和结束作为切点做切入处理增强。当动态代理对象最终调用的原始对象的目标方法时,并不能干预到目标方法内的方法调用行为,如果原始对象直接调用(用this.xxx方式)其他同类方法时,实际调用的是原始对象自身的方法,而不是代理类对象增强后(增加事务控制后)的方法。此时Spring对方法事务的控制(包括事务的传播行为、事务的隔离级别等)完全失效。

如何解决?
要想解决此类问题,主要都在于原始对象在调用对象内其他方法时,不要使用this.xxx的方式直接调用,通过注入或者获取代理对象的方式,使用代理对象调用需要调用的方法。下面列举几个解决方式:

1.注入自身,使用代理对象调用

@Servicepublic class DemoService { 

@Autowired DemoService demoService;

@Transactionpublic void transactionMethod1() {  op1(); op2(); ... } 

public void commonMethod() {  ...//this.transactionMethod1() -> demoService.transactionMethod1()  demoService.transactionMethod1();  ...  } }

2.使用AopContext,获取当前代理对象

@Servicepublic class DemoService {

@Transactionpublic void transactionMethod1() {  op1(); op2(); ... } 

public void commonMethod() {  ...//this.transactionMethod1() -> ((DemoService)AopContext.currentProxy()).transactionMethod1();)  ((DemoService)AopContext.currentProxy()).transactionMethod1(); ...  } 

 ...}

3.使用BeanFactory获取代理对象(代码略)

欢迎关注“Java引导者”,我们分享最有价值的Java的干货文章,助力您成为有思想的的Java开发工程师!

spring的事务隔离_spring事务基础及常见问题详解相关推荐

  1. 【机器学习】机器学习基础知识常见问题详解!

    作者:胡联粤,Datawhale面经小组 Q1 ⽼板给了你⼀个关于癌症检测的数据集,你构建了⼆分类器然后计算了准确率为 98%, 你是否对这个模型满意?为什么?如果还不算理想,接下来该怎么做? 首先模 ...

  2. 事务的传播特性之@Transactional使用详解

    事务的传播特性之@Transactional使用详解 一.@Transactional 7个传播特性 常用配置参数 二.编码详解 1.准备基础代码 2.REQUIRED 3.SUPPORTS 4.MA ...

  3. Redis基础及原理详解

    Redis基础及原理详解 前言:以下是最近学习redis的一些笔记总结,文中如有不当的地方欢迎批评指正,重在记录与学习,笔芯~~ Nosql概述 演进历史 单机mysql Memcached(缓存)+ ...

  4. 基础拾遗------webservice详解

    基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...

  5. elastic stack 基础组件beats详解

    elastic stack 基础组件beats详解 fielbeat filebeat: spool_size: 1024 # 最大可以攒够 1024 条数据一起发送出去 idle_timeout: ...

  6. 基础排序算法详解与优化

    文章图片存储在GitHub,网速不佳的朋友,请看<基础排序算法详解与优化> 或者 来我的技术小站 godbmw.com 1. 谈谈基础排序 常见的基础排序有选择排序.冒泡排序和插入排序.众 ...

  7. java中属性文件读取案例_java相关:Spring中属性文件properties的读取与使用详解

    java相关:Spring中属性文件properties的读取与使用详解 发布于 2020-6-3| 复制链接 摘记: Spring中属性文件properties的读取与使用详解实际项目中,通常将一些 ...

  8. 基础拾遗------委托详解

    基础拾遗: 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗---- ...

  9. Spring Cloud Eureka 入门 (三)服务消费者详解

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! "真正的进步 ...

最新文章

  1. aidl生成java文件_Android Studio编写AIDL文件后如何实现自动编译生成
  2. SAP QM高阶之检验点(Inspection Point)
  3. 让产品有效迭代,前端A/B Testing的简单实现
  4. 启明云端分享| 2.4寸磁编码旋钮屏
  5. OpenCV SURF FLANN匹配单应性的实例(附完整代码)
  6. 网络编程之---广播和IP多播
  7. 工业交换机和商用交换机对比
  8. web版本 开源压测工具_siege--Web性能压测工具
  9. java常见异常类图(分类了Error/RuntimeExecption、check Exception)
  10. sumo的简单应用_sumo快速运行简单仿真实例详细教程
  11. Java:Eclipse下载安装教程,以及Eclipse 安装汉化包的方法
  12. 动态桌面壁纸软件:iWall for Mac
  13. 网易云音乐打卡听歌300首源码
  14. TVS管参数说明以及如何选型
  15. 3dmax如何删除多余的时间帧
  16. 对游戏编程开发的一点思考
  17. 【环境搭建】win10 AMD显卡 opencl环境搭建
  18. 博客园Training Team加入申请帖
  19. Kotlin自定义android 控件
  20. Maven概念,项目目录结构

热门文章

  1. c语言编程软件有个a开头的,厦门理工软件c语言程序设计A卷及答案
  2. 苹果手机显示iphone已停用连接itunes_iphone忘记密码怎么办 iphone忘记密码解决方法【详细步骤】...
  3. html小球跳跃技术原理,HTML5在文本上跳跃的小球
  4. oracle升级后报 06502,Oracle数据库升级后报ORA-00704和ORA-39700错误
  5. php pdo query 空判断,检查空结果(php,pdo,mysql)
  6. leetcode 75
  7. ADT 压缩包 R23.0.0
  8. WebApi 数据保护操作未成功。这可能是由于未为当前线程的用户上下文加载用户配置文件导致的。当线程执行模拟时,可能会出现此情况。,ExceptionType:System.Security....
  9. hdu 4578 Transformation(线段树)
  10. 过年啦!抽奖发2022元红包!