事务管理是应用系统开发中必不可少的一部分。事物将若干的数据库操作作为一个整体控制,一起成功或一起失败。事物有以下特性

原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
  一致性:指事务前后数据的完整性必须保持一致。
  隔离性:指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离。
  持久性:指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,即时数据库发生故障也不应该对其有任何影响。

Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编码式和声明式的两种方式。编程式事务指的是通过编码方式实现事务;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污染, 因此在实际使用中声明式事务用的比较多。声明式事务有两种方式,一种是在配置文件(xml)中做相关的事务规则声明,另一种是基于@Transactional 注解的方式。注释配置是目前流行的使用方式,因此本文将着重介绍基于@Transactional 注解的事务管理。

@Transactional 注解的属性信息
属性名 说明
name 当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。
propagation 事务的传播行为,默认值为 REQUIRED。
isolation 事务的隔离度,默认值采用 DEFAULT。
timeout 事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
read-only 指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
rollback-for 用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。
no-rollback- for 抛出 no-rollback-for 指定的异常类型,不回滚事务。

事物传播行为:


  • REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
  • SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
  • MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
  • REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
  • NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
  • NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与REQUIRED类似的操作。拥有多个可以回滚的保存点,内部回滚不会对外部事务产生影响。只对DataSourceTransactionManager有效

事物隔离级别


  •   DEFAULT--使用后端数据库默认的隔离级别(Spring中的选择项)
  • READ_UNCOMMITED--允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读
  • READ_COMMITTED--允许在并发事务已经提交后读取。可防止脏读,但幻读和不可重复读仍可发生(锁定正在读取的行)
  • REPEATABLE_READ--对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生(锁定所读取的所有行)
  • SERIALIZABLE--完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的 (锁表

其中,MySQL默认采用REPEATABLE_READ隔离级别;Oracle默认采用READ_COMMITTED隔离级别

依据事务的隔离级别将会有三种情况发生。

  脏读:一个事务会读进还没有被另一个事务提交的数据,所以你会看到一些最后被另一个事务回滚掉的数据。

  不可重复读:一个事务读进一条记录,另一个事务更改了这条记录并提交完毕,这时候第一个事务再次读这条记录时,它已经改变了

  幻影读:一个事务用Where子句来检索一个表的数据,另一个事务插入一条新的记录,并且符合Where条件,这样,第一个事务用同一个where条件来检索数据后,就会多出一条记录

我们首先先实验事务的传播

注意:所有的测试都是调用method1

public void method1() {
TicketEntity ticketEntity = new TicketEntity();
ticketEntity.setF_apply_service("测试");
ticketEntityMapper.insertSelective(ticketEntity);
method2(ticketEntity.getF_ticket_id());
throw new RuntimeException("事务需要回滚"); } @Transactional(propagation = Propagation.REQUIRED)
public void method2(Integer id) {
TicketEntity ticketEntity = new TicketEntity();
ticketEntity.setF_apply_service("测试2");
ticketEntityMapper.insertSelective(ticketEntity);
}

结果:都不回滚

public void method1() {
TicketEntity ticketEntity = new TicketEntity();
ticketEntity.setF_apply_service("测试");
ticketEntityMapper.insertSelective(ticketEntity);
method2();
// throw new RuntimeException("事务需要回滚"); } @Override
@Transactional(propagation = Propagation.REQUIRED)
public void method2() {
TicketEntity ticketEntity = new TicketEntity();
ticketEntity.setF_apply_service("测试2");
ticketEntityMapper.insertSelective(ticketEntity);
throw new RuntimeException("事务需要回滚");
}

结果:都不回滚

// @Transactional(propagation = Propagation.REQUIRED)
public void method1() {
TicketEntity ticketEntity = new TicketEntity();
ticketEntity.setF_apply_service("测试");
ticketEntityMapper.insertSelective(ticketEntity);
method2();
// throw new RuntimeException("事务需要回滚"); } @Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void method2() {
TicketEntity ticketEntity = new TicketEntity();
ticketEntity.setF_apply_service("测试2");
ticketEntityMapper.insertSelective(ticketEntity);
throw new RuntimeException("事务需要回滚");
}

结果:都不回滚

@Transactional(propagation = Propagation.REQUIRED)
public void method1() {
TicketEntity ticketEntity = new TicketEntity();
ticketEntity.setF_apply_service("测试");
ticketEntityMapper.insertSelective(ticketEntity);
method2();
// throw new RuntimeException("事务需要回滚"); } @Override
// @Transactional(propagation = Propagation.REQUIRED)
public void method2() {
TicketEntity ticketEntity = new TicketEntity();
ticketEntity.setF_apply_service("测试2");
ticketEntityMapper.insertSelective(ticketEntity);
throw new RuntimeException("事务需要回滚");
}

结果:回滚

@Transactional(propagation = Propagation.REQUIRED)
public void method1() { TicketEntity ticketEntity = new TicketEntity();
ticketEntity.setF_apply_service("测试");
ticketEntityMapper.insertSelective(ticketEntity);
method2();
// throw new RuntimeException("事务需要回滚1");
} @Override
@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
public void method2() {
TicketEntity ticketEntity = new TicketEntity();
ticketEntity.setF_apply_service("测试2");
ticketEntityMapper.insertSelective(ticketEntity);
// throw new RuntimeException("事务需要回滚2");
}

结果:不回滚,如果直接调用method2,则会报错,说明自调用时注解时没有效果的。

在 Spring 的 AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会造成自调用问题。若同一类中的其他没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,有@Transactional 注解的方法的事务被忽略,不会发生回滚。

这是由于使用 Spring AOP 代理造成的。为解决这两个问题,使用 AspectJ 取代 Spring AOP 代理。

Spring 事务传播实践分析的更多相关文章

  1. spring事务传播实现源码分析

    转载. https://blog.csdn.net/qpfjalzm123/article/details/83717367 本文只是对spring事务传播实现的流程进行简单的分析,如有不对之处请指出 ...

  2. spring 事务传播行为实例分析

    Spring事务传播行为: spring特有的事务传播行为,spring支持7种事务传播行为,确定客户端和被调用端的事务边界(说得通俗一点就是多个具有事务控制的service的相互调用时所形成的复杂的 ...

  3. spring事务传播特性实验(2):PROPAGATION_REQUIRED实验结果与分析

    本文延续上一文章(spring事务传播特性实验(1):数据准备),在已经准备好环境的情况下,做如下的实验,以验证spring传播特性,加深对spring传播特性的理解. 本次主要验证PROPAGATI ...

  4. spring事务传播机制实例讲解

    http://kingj.iteye.com/blog/1680350   spring事务传播机制实例讲解 博客分类:   spring java历险     天温习spring的事务处理机制,总结 ...

  5. Spring事务传播机制

    Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播,即协调已经有事务标识的方法之间的发生调用时的事务 ...

  6. Spring事务传播机制和数据库隔离级别

    Spring事务传播机制和数据库隔离级别 转载 2010年06月26日 10:52:00 标签: spring / 数据库 / exception / token / transactions / s ...

  7. Spring事务传播属性介绍(二).mandatory、not_supported、never、supports

    Required.Required_New传播属性分析传送门:https://www.cnblogs.com/lvbinbin2yujie/p/10259897.html Nested传播属性分析传送 ...

  8. Spring事务传播属性介绍(三).Nested

    Required.Required_New传播属性分析传送门:https://www.cnblogs.com/lvbinbin2yujie/p/10259897.html Mandatory.Neve ...

  9. Spring事务传播属性介绍(一).required 和 reuqires_new

    Mandatory.Never.Not_Support传播属性分析传送门:https://www.cnblogs.com/lvbinbin2yujie/p/10260030.html Nested传播 ...

随机推荐

  1. 五分钟让你读懂UML常见类图

    相信各位同学在阅读一些源码分析类文章或是设计应用架构时没少与UML类图打交道.实际上,UML类图中最常用到的元素五分钟就能掌握,经常看到UML类图但还不太熟悉的小伙伴赶紧来一起认识一下它吧:)   一 ...

  2. APP动态加载轮播图片

    如果APP里面的轮播图片是动态加载的话,那么你会发现他不会轮播(前提是mui框架),这里都是用的mui框架,动态加载的图片因为mui的js查不到html上面没有图片,所以就不会轮播,需要手动重置下轮播 ...

  3. Java平台

    Java的平台无关性 不同的网络环境,操作系统 支持嵌入式设备 减少开发部署时间 Java自身的平台和语言 编译成class文件 可在Java虚拟机中运行,与外部环境无关(对虚拟机的依赖) 通过外部A ...

  4. Self Attention需要掌握的基本原理

    字面意思理解,self attention就是计算句子中每个单词的重要程度. 1. Structure 通过流程图,我们可以看出,首先要对输入数据做Embedding 1. 在编码层,输入的word- ...

  5. lombok学习

    lombok的官方地址:https://projectlombok.org/ lombok的Github地址:https://github.com/rzwitserloot/lombok lombok ...

  6. CodeForces 935E Fafa and Ancient Mathematics (树形DP)

    题意:给定一个表达式,然后让你添加 n 个加号,m 个减号,使得表达式的值最大. 析:首先先要建立一个表达式树,这个应该很好建立,就不说了,dp[u][i][0] 表示 u 这个部分表达式,添加 i ...

  7. 数据的描述性分析_R

    1. 生成二维数据(类别型数据)的列联表 (1) mytable<-table(data)/prop.table(概率) addmargins(mytable) (2) library(gmod ...

  8. 架构(四)Git简介,安装以及相关命令SourceTree

    一 Git介绍 1.1 Git是什么? Git是一个分布式版本控制软件: 版本控制:假如开发人员开发了一个a功能,结果项目经理觉得不够需要修改,开发人员又改成了b功能,后来又改成了c功能,但是最终项目 ...

  9. spring整合mybatis二种配置

    第一种: <!-- 配置sqlsession --> <bean id="sqlsessionFactory" class="org.mybatis.s ...

  10. 背水一战 Windows 10 (117) - 后台任务: 后台下载任务

    [源码下载] 背水一战 Windows 10 (117) - 后台任务: 后台下载任务 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台下载任务 示例演示 uwp 的后台下 ...