一文搞懂什么是事务

一文搞懂什么是事务

目录
  • 一文搞懂什么是事务

    • 事务概念
    • 脏读、不可重复读、幻读
      • 脏读
      • 不可重复读(前后多次读取,数据内容不一致)
      • 幻读(前后多次读取,数据总量不一致)
    • 数据库事务的隔离级别
      • DEFAULT
      • READ UNCOMMITTED(读未提交)
      • READ_COMMITTED (读提交)
      • REPEATABLE_READ (可重复读)
      • SERIALIZABLE (串行化)
        • MVCC(多版本并发控制)
    • Spring事务传播行为
    • Spring 事务的两种实现
      • 两种事务管理间的区别
      • Spring 编程式事务
      • Spring 声明式事务
        • 常用的声明式事务使用方法
        • @Transactional 的作用范围
        • @Transactional 注解中可配置参数
        • 示例
    • 使用事务时需要注意的点
    • 总结

事务概念

我们要理解下事务概念: 什么是事务呢?事务是并发控制的单位,是用户定义的一个操作序列。有四个特性(ACID):

  • 原子性(Atomicity): 事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做。

  • 一致性(Consistency): 事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

  • 隔离性(Isolation): 一个事务的执行不能被其他事务干扰。

  • 持续性/永久性(Durability): 一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。

以上是书面解释,简单来说就是把你的操作统一化,要么所有操作都成功,要么就都不成功,如果执行中有某一项操作失败,其之前所有的操作都回滚到未执行这一系列操作之前的状态。

脏读、不可重复读、幻读

先理解这三种由于并发访问导致的数据读取问题,再理解事务隔离级别就简单多了。

脏读

A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据。就好像原本的数据比较干净、纯粹,此时由于B事务更改了它,这个数据变得不再纯粹。这个时候A事务立即读取了这个脏数据,但事务B良心发现,又用回滚把数据恢复成原来干净、纯粹的样子,而事务A却什么都不知道,最终结果就是事务A读取了此次的脏数据,称为脏读。

这种情况常发生于转账与取款操作中

不可重复读(前后多次读取,数据内容不一致)

事务A在执行读取操作,由整个事务A比较大,前后读取同一条数据需要经历很长的时间 。而在事务A第一次读取数据,比如此时读取了小明的年龄为20岁,事务B执行更改操作,将小明的年龄更改为30岁,此时事务A第二次读取到小明的年龄时,发现其年龄是30岁,和之前的数据不一样了,也就是数据不重复了,系统不可以读取到重复的数据,成为不可重复读。

幻读(前后多次读取,数据总量不一致)

事务A在执行读取操作,需要两次统计数据的总量,前一次查询数据总量后,此时事务B执行了新增数据的操作并提交后,这个时候事务A读取的数据总量和之前统计的不一样,就像产生了幻觉一样,平白无故的多了几条数据,成为幻读。

小总结:不可重复读和幻读到底有什么区别?

(1) 不可重复读是读取了其他事务更改的数据,针对update操作

解决:使用行级锁,锁定该行,事务A多次读取操作完成后才释放该锁,这个时候才允许其他事务更改刚才的数据。

(2) 幻读是读取了其他事务新增的数据,针对insert和delete操作

解决:使用表级锁,锁定整张表,事务A多次读取数据总量之后才释放该锁,这个时候才允许其他事务新增数据。

这时候再理解事务隔离级别就简单多了呢。

数据库事务的隔离级别

SQL 标准定义的四种隔离级别被 ANSI(美国国家标准学会)和 ISO/IEC(国际标准)采用,每种级别对事务的处理能力会有不同程度的影响。事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。

数据库事务的隔离级别有4个,由低到高依次为Read uncommitted 、Read committed 、Repeatable read 、Serializable ,这四个级别可以逐个解决脏读 、不可重复读 、幻读 这几类问题。

DEFAULT

默认值,表示使用底层数据库的默认隔离级别。大部分数据库为READ_COMMITTED(MySql默认REPEATABLE_READ)

READ UNCOMMITTED(读未提交)

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

READ_COMMITTED (读提交)

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

REPEATABLE_READ (可重复读)

该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。

SERIALIZABLE (串行化)

所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 在该隔离级别下事务都是串行顺序执行的,MySQL 数据库的 InnoDB 引擎会给读操作隐式加一把读共享锁,从而避免了脏读、不可重读复读和幻读问题。

MVCC(多版本并发控制)

mysql中,默认的事务隔离级别是可重复读(repeatable-read),为了解决不可重复读,innodb采用了MVCC(多版本并发控制)来解决这一问题。
MVCC是利用在每条数据后面加了隐藏的两列(创建版本号和删除版本号),每个事务在开始的时候都会有一个递增的版本号,用来和查询到的每行记录的版本号进行比较。 MYSQL MVCC

Spring事务传播行为

先来介绍下Spring事务传播行为的使用方法:

@Transactional(propagation=Propagation.REQUIRED)public void test() {        //todo something}

注解@Transactional
通过使用 propagation 属性设置,例如:@Transactional(propagation = Propagation.REQUIRED)

它的propagation属性取值有以下几种:

public enum Propagation {    REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),    SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),    MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),    REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),    NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),    NEVER(TransactionDefinition.PROPAGATION_NEVER),    NESTED(TransactionDefinition.PROPAGATION_NESTED);}

事务传播行为:

  • REQUIRED :如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • SUPPORTS :如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • MANDATORY :如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • REQUIRES_NEW :创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • NOT_SUPPORTED :以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • NEVER :以非事务方式运行,如果当前存在事务,则抛出异常。
  • NESTED :如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 REQUIRED

Spring 事务的两种实现

Spring 支持“编程式事务”管理和“声明式事务”管理两种方式:

1编程式事务: 编程式事务使用 TransactionTemplate 或者直接使用底层的 PlatformTransactionManager 实现事务。 对于编程式事务 Spring 比较推荐使用 TransactionTemplate 来对事务进行管理。

2声明式事务: 声明式事务是建立在 AOP 之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况“提交”或者“回滚”事务。

两种事务管理间的区别

  • 编程式事务允许用户在代码中精确定义事务的边界。
  • 声明式事务有助于用户将操作与事务规则进行解耦,它是基于 AOP 交由 Spring 容器实现,是开发人员只重点关注业务逻辑实现。
  • 编程式事务侵入到了业务代码里面,但是提供了更加纤细的事务管理。而声明式事务基于 AOP,所以既能起到事务作用,又可以不影响业务代码的具体实现。一般而言比较推荐使用声明式事务,尤其是使用 @Transactional 注解,它能很好地帮助开发者实现事务的同时,也减少代码开发量,且使代码看起来更加清爽整洁。

Spring 编程式事务

一般来说编程式事务有两种方法可以实现:
模板事务的方式(TransactionTemplate)平台事务管理器方式(PlatformTransactionManager)

  • 模板事务的方式(TransactionTemplate): 主要是使用 TransactionTemplate 类实现事务,这也是 Spring 官方比较推荐的一种编程式使用方式;

例:

  • ① 获取模板对象 TransactionTemplate;
  • ② 选择事务结果类型;
  • ③ 业务数据操作处理;
  • ④ 业务执行完成事务提交或者发生异常进行回滚;

其中 TransactionTemplate 的 execute 能接受两种类型参数执行事务,分别为:

 TransactionCallback<Object>(): 执行事务且可以返回一个值。 TransactionCallbackWithoutResult(): 执行事务没有返回值。

下面是使用 TransactionTemplate 的实例:

@Servicepublic class TransactionExample {  /** 1、获取 TransactionTemplate 对象 **/  @Autowired  private TransactionTemplate transactionTemplate;    public void addUser() {      // 2、使用 TransactionCallback 或者 TransactionCallbackWithoutResult 执行事务      transactionTemplate.execute(new TransactionCallbackWithoutResult() {          @Override          public void doInTransactionWithoutResult(TransactionStatus transactionStatus) {              try {                  // 3、执行业务代码(这里进行模拟,执行多个数据库操作方法)                  userMapper.delete(1);                  userMapper.delete(2);              } catch (Exception e) {                  // 4、发生异常,进行回滚                  transactionStatus.setRollbackOnly();              }          }      });  }  }

  • 平台事务管理器方式(PlatformTransactionManager): 这里使用最基本的事务管理局对事务进行管理,借助 Spring 事务的 PlatformTransactionManager 及 TransactionDefinition 和 TransactionStatus 三个核心类对事务进行操作。

使用事务管理器方式实现事务步骤:

  • ① 获取事务管理器 PlatformTransactionManager;
  • ② 获取事务属性定义对象 TransactionDefinition;
  • ③ 获取事务状态对象 TransactionStatus;
  • ④ 业务数据操作处理;
  • ⑤ 进行事务提交 commit 操作或者发生异常进行事务回滚 rollback 操作;
@Servicepublic class TransactionExample {        /** 1、获取 PlatformTransactionManager 对象 **/    @Autowired    private PlatformTransactionManager platformTransactionManager;    public void addUser() {        // 2、获取默认事务定义        DefaultTransactionDefinition def = new DefaultTransactionDefinition();        // 设置事务传播行为        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);        // 3、根据事务定义对象设置的属性,获取事务状态        TransactionStatus status = platformTransactionManager.getTransaction(def);        try {            // 4、执行业务代码(这里进行模拟,执行多个数据库操作方法)            userMapper.delete(1);            userMapper.delete(2);            // 5、事务进行提交            platformTransactionManager.commit(status);        } catch(Exception e){            // 5、事务进行回滚            platformTransactionManager.rollback(status);        }    }    }

Spring 声明式事务

声明式事务(declarative transaction management)顾名思义就是使用声明的方式来处理事务。该方式是基于 Spring AOP 实现的,将具体业务逻辑和事务处理解耦,其本质是在执行方法前后进行拦截,在方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

常用的声明式事务使用方法

常用的声明式事务使用方法有

  • 1 XML
  • 2 @Transactional 注解

两种方法,由于近几年 SpringBoot 的流行,提供很方便的自动化配置,致使 XML 方式已经逐渐淘汰,比较推荐使用注解的方式

@Transactional 的作用范围

注解 @Transactional 不仅仅可以添加在方法上面,还可以添加到类级别上,当注解放在类级别时,表示所有该类的公共方法都配置相同的事务属性信息。如果类级别配置了 @transactional,方法级别也配置了 @transactional,应用程序会以方法级别的事务属性信息来管理事务,换言之,方法级别的事务属性信息会覆盖类级别的相关配置。

@Transactional 注解中可配置参数
  • value: 事务管理器,此配置项是设置 Spring 容器中的 Bean 名称,这个 Bean 需要实现接口 PlatformTransactionManager。
  • transactionManager: 事务管理器,该参数和 value 配置保持一致,是同一个东西。
  • isolation: 事务隔离级别,默认为 Isolation.DEFAULT 级别
  • propagation: 事务传播行为,默认为 Propagation.REQUIRED
  • timeout: 事务超时时间,单位为秒,默认值为-1,当事务超时时会抛出异常,进行回滚操作。
  • readOnly: 是否开启只读事务,是否开启只读事务,默认 false
  • rollbackForClassName: 回滚事务的异常类名定义,同 rollbackFor,只是用类名定义。
  • noRollbackForClassName: 指定发生哪些异常名不回滚事务,参数为类数组,同 noRollbackFor,只是使用类的名称定义。
  • rollbackFor: 回滚事务异常类定义,当方法中出异常,且异常类和该参数指定的类相同时,进行回滚操作,否则提交事务。
  • noRollbackFor: 指定发生哪些异常不回滚事务,当方法中出异常,且异常类和该参数指定的类相同时,不回滚而是将继续提交事务。
示例
@Transactional(propagation=Propagation.REQUIRED)public void test() {        //todo something}

注意:
一般而言,不推荐将 @Transaction 配置到类上,因为这样很可能使后来的维护人员必须强制使用事务。

使用事务时需要注意的点

  • 1、遇到异常检测不回滚,原因:默认RuntimeException级别才回滚,如果是Eexception级别的异常需要手动添加
@Transactional(rollbackFor=Exception.class)
  • 2、捕捉异常后事物不生效,原因:捕捉处理了异常导致框架无法感知异常,自然就无法回滚了。建议:若非实际业务要求,则在业务层统一抛出异常,然后在控制层统一处理
@Transactional(rollbackFor=Exception.class)public void test() {    try {         //业务代码    } catch (Exception e) {        // TODO: handle exception    }   //主动捕捉异常导致框架无法捕获,从而导致事物失效}

总结

本章主要讲了 事务基本概念ACID是什么
,脏读、不可重复读、幻读 等等术语的介绍及例子
数据库事务的隔离级别(4种),
Spring事务传播行为(7种),事务的实现实例和使用事务时需要注意的地方 通过这篇文章,小伙伴们应该已经对事务有了更深的了解吧 ,最后 欢迎关注我的公众号:JAVA宝典 或者加我的微信 我们一起探讨和学习.

关注公众号:java宝典

(0)

相关推荐

  • Java Spring三剑客(十二月赠书福利)

    今日推荐   加小编微信(cxycode) 备注:加群 邀请加入程序员技术群 机器人自动邀请的  Spring系列图书推荐:(文末赠书活动,不要错过了) Spring其中一个强大之处在于,他是支持声明 ...

  • Spring事务总结

    Spring事务总结

  • (十二)Spring从入门到入土——Spring事务

    Spring事务 事务是逻辑上的一组操作,要么都执行,要么都不执行 事务的特性(ACID) 原子性 一致性 隔离性 持久性 Spring管理事务的方式有几种 程序是否支持事务是取决于数据库是否支持事务 ...

  • Spring 事务介绍

    一.简介 接着上篇 数据库事务简介,来聊聊 Spring 事务. Spring 本身并不实现事务,Spring 事务的本质还是底层数据库对事务的支持,没有数据库事务的支持,Spring 事务就不会生效 ...

  • mysql事务隔离级别和spring Transaction事务传播

    事务的ACID原则是什么? 原子性(atomicity):最小且不可分割的.要么都执行,要么都不执行. 一致性(consistency):事务的执行使得数据库从一种正确状态转换成另一种正确状态 隔离型 ...

  • 收藏!一文搞懂“顺周期”概念股!(名单)

    2020-11-17 19:01 导读 周期股近期表现抢眼,那到底什么是周期行业?为何被追捧?相关概念股有哪些? 近期热点涣散之下,"煤飞色舞钢花溅"行情再现.今日盘面上,煤炭.有 ...

  • 一文搞懂爬架如何管理

    愿    景:让天下没有难做的工程! 使    命:推动工程管理的创新和技术变革! 价 值 观:成就他人.成长自己! 宗旨目的:致力于成为工程人的知识共享平台,让沟通无障碍.让学习更快捷!  觉得文章 ...

  • 一文搞懂黎曼假设,解析数论的里程碑,质数理论的珠穆朗玛

    还记得质数吧?这是一个3000年前的问题: 2.3.5.7 .11.13 .17 .19 .23 .29. p.p是什么?31.下一个p是什么?这是37.后面的p呢?41..然后呢?43.但是,你怎么 ...

  • 一文搞懂麦克斯韦方程,现代科技的总基石,人类文明的加速器

    在我们开始之前,请注意,以任何有意义的方式讨论电磁学就意味着要讨论向量演算.请不要害怕,即使你不知道任何符号和术语的意思.向量微积分很难,但它的核心思想是直观的,我会在接下来的过程中解释一切. 在国际 ...

  • 一文搞懂“子午流注”与经气运行的关系

    人与自然界息息相关,就是说人体时时刻刻都在与自然界进行交流.所以<素问·六节藏象论>中指出:"天食人以五气,地食人以五味--气和而生,津液相成,神乃自生".说明了天供人 ...

  • 电缆BV、BLV、VV、VLV、KVV分别代表什么意思?一文搞懂!

    学造价网 建筑工程造价学习.交流知识平台公众号来源:电气圈如有侵权,请联系删除 1 电线电缆中BV.BLV等符号含义这些符号都是电线的一些型号,B系列归类属于布电线,所以开头用B,电压:300/500 ...

  • 中医:一文搞懂三焦辨证的主要内容

    吴鞠通沿用了<内经><难经>三焦之名,参照三焦的生理功能和病理变化,借用的是<灵枢·营卫生会><难经·三十一难>的三焦分部概念(即上焦病为手太阴肺和手厥 ...

  • 一文搞懂肾精、肾气与肾阴阳之间的联系与区别

    点击加载图片 一.肾精 肾为脏腑之本,生命之源,是因其具有藏精功能所决定的.肾所藏之精叫做肾精,精又能化气,而肾之精气的盛衰,关系到人体生长发育及衰老.换言之.人的生,长.壮.老规律是由肾的精气盛衰所 ...

  • 中医:一文搞懂人体的诸气之首

    宗气,是由经脾胃消化.吸收而来的水谷精微之气与从自然界吸入的清气结合而成.宗气在胸中积聚之处,称作"上气海",又名膻中.向下赖肺之肃降而蓄于丹田(下气海),并注人足阳明之气街(相当 ...