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

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

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. 前端面试题---vue部分

    1.vue的两大核心思想 组件化和数据驱动 2.如何理解vue中的MVVM模式 Model-View-ViewModel(简称为mvvm)是一种设计思想,model层代表数据模型,也可以再model中 ...

  2. Liang-Barsky直线段裁剪算法

    Liang-Barsky直线段裁剪算法 梁友栋与Barsky提出的裁剪算法以直线的参数方程为基础,把判断直线段与窗口边界求交的 二维裁剪问题转化为求解一组不等式,确定直线段参数的一维裁剪问题.设起点为 ...

  3. centos 6.5升级openssl

    1.下载升级版本 wget https://www.openssl.org/source/openssl-1.1.0i.tar.gz 2.安装 zlib zlib-devel yum -y insta ...

  4. springboot整合redis-sentinel支持Cache注解

    一.前提 已经存在一个redis-sentinel集群,两个哨兵分别如下: /home/redis-sentinel-cluster/sentinel-1.conf port 26379 dir &q ...

  5. JavaScript基础视频教程总结(131-140章)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  6. IO流的种类

    字节流:InputStream(new FileInputStream(new File()); Outpustream(new FileOutputStream(new File()); 字符流:  ...

  7. 怎么解决syntaxerror:non-utf-8 code starting with \xc4'in file

    怎么解决syntaxerror:non-utf-8 code starting with \xc4'in file   首行增加,已测试可用. # coding=gbk   程序中出现中文,运行的时候 ...

  8. 【洛谷P2584】【ZJOI2006】GameZ游戏排名系统题解

    [洛谷P2584][ZJOI2006]GameZ游戏排名系统题解 题目链接 题意: GameZ为他们最新推出的游戏开通了一个网站.世界各地的玩家都可以将自己的游戏得分上传到网站上.这样就可以看到自己在 ...

  9. 阿里云Centos+Django+Nginx+uWSGI

    针对系统中自带的Python2.7版本 1.安装python-devel yum install python-devel 2.安装uwsgi pip install uwsgi 3.测试uwsgi是 ...

  10. 两台Linux机器传送文件

    https://www.cnblogs.com/lianrenjujishou/p/5458206.html