初识事务,事务隔离级别,事务传播行为

本篇文章会介绍以下几个概念:事务,事务隔离级别,spring事务的传播模式。在介绍事务时会引出原子性的概念,在介绍事务隔离级别的时候会引出脏读和幻读的概念。

事务

什么是事务?

事务最开始是数据库中的概念,它把一系列的操作统一为一个整体,这一系列的操作要么同时成功,要么同时失败。一个事务基本的操作是:

  1. 开启事务
  2. 如果发生了错误,进行回滚
  3. 如果没有发生错误,则提交事务

为什么要有事务?

在我们处理简单业务的时候,比如说一条插入数据的操作,只会得到两个结果,要么插入成功,要么插入失败,这对应到代码逻辑上是很简单的。
我们称这样的操作具有原子性。

但是我们的业务往往不会只有插入一条数据那么简单,可能用户点击一个按钮后,我们需要插入一条数据和删除一条数据。由于每个操作都有可能成功和失败,这个时候我们就有了2^2=4种情况,这下编程起来就麻烦了。

为了方便编程(也为了符合实际业务逻辑),我们引入开头所述的事务机制,把两个操作放在一个事务里面,使这两个操作具备原子性,这样一来业务处理起来就方便多了。

事务隔离级别

上面我们谈到了操作数据库的时候会使用到事务,接下来引入的问题就是:在数据库中,难免会出现多个事务同时操作数据的情况,这时数据库设置的事务隔离级别不同,会出现不同的数据操作结果,经典的脏读与幻读也诞生于此。

首先给出并发访问时,不同事务隔离级别下的情况表:

事务隔离级别 脏读 不可重复读 幻读
read uncommitted 读未提交
read committed 读提交 不会
repeatable read 可重复读 不会 不会
serializable 串行化 不会 不会 不会

可以看到事务隔离级别越高,产生的问题越少,但是相应的性能是会降低的,下面通过几个例子分别阐述不同事务隔离级别下发生的问题:

读未提交

当事务隔离设置为读未提交时,最容易产生的问题是脏读。读未提交指的是当前事务可以读到其他事务未提交的数据:假设一位父亲给他的儿子打生活费,本来一个月2000但是不小心手抖多打了1000变成3000,这时儿子去商店消费,查询余额的时候就多了3000。由于父亲的事务还没提交,便立马回滚事务,重新打过去2000生活费。

这个时候儿子读到的余额就是脏数据,产生的原因是读取了其他事务未提交的数据。

读提交

只要将事务隔离级别设置为读提交就能解决上面的脏读问题,他能保证当前事务只能读到其他事务已经提交的数据。但是读提交会面临一个新问题:不可重复读。

比如说儿子拿着卡到商店消费,买单的时候(开启当前事务),系统检测到卡里只有500元。这个时候父亲给儿子转了2000块生活费,当儿子准备扣费的时候再查询余额发现变成了2500元(这个查询发生在父亲的转账事务提交之后)

在同一个事务中,儿子的余额在不同的时候读取的值不一样,这就是不可重复读问题。想要解决这个问题,需要把事务隔离级别设置为可重复读

可重复读

在可重复读的情况下,当前事务会禁止其他事务对正在操作的数据进行更新,这样一来,父亲转账的事务就要等到儿子账号扣费结束后才能进行,从此解决了不可重复读问题。

但是可重复读级别下还可能发生一个问题叫幻读,举例如下:儿子今天在外消费了1000元,父亲查看儿子一天的消费记录(开启事务),发现一共是1000元。这个时候儿子又消费了1000元(父亲的事务仍在进行中),接着父亲打印儿子今天的消费记录,发现莫名其妙地变成了2000元,多了一条消费记录。

像这种当前事务在操作的过程中,由于别的事务增加或删除数据,导致当前事务操作的数据突然变多或变少的情况,就叫幻读。想要解决幻读,需要把事务隔离级别升级为串行化

串行化

当事务隔离级别为串行化时,所有事务都是串行执行的,对应上面的例子:父亲在查看当天消费记录时,儿子是不能消费的。这么一来事务并发带来的问题都能解决,但是效率很低。

扩展

在常用的数据库中Orcale默认的事务隔离级别是读提交,而Mysql默认的是可重复读。在Mysql的InnoDB引擎中,虽然事务隔离级别是可重复读,但是也可以解决幻读问题,背后的原理是在数据行之间添加间隙锁,防止数据的插入与删除。

具体选择那一种事务隔离级别,要看具体的业务需要

事务传播行为

事务的传播行为从字面上也是挺好理解的:想要发生传播就一定要有两个以上的物体,而这里指的是两个方法都要在事务中进行,当一个事务方法A调用另一个事务方法B时,另一个事务方法B该如何运行。

Spring一共定义了7种事务传播行为(事务方法B该如何运行):

传播行为 含义
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中(这是最常见的选择,也是spring的默认事务传播行为)
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作

平时我们最常用的是 PROPAGATION_REQUIRED,这也是spring的默认事务传播行为,理解了它就能按理推导其他的事务传播行为。

比如说当前我们有如下代码:

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
     methodB();
    // do something
}

@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
    // do something
}
  1. 假设我们执行methodA,由于当前还没有事务,于是就新创建一个事务。
  2. 当在methodA中调用methodB的时候,由于methodA已经存在于事务中,于是methodB便无需新创建一个事务,直接加入到methodA的事务中即可。

总结

  1. 事务能够让一系列不同的操作具有原子性。(当然事务具备ACID四大特性,本文在初步介绍时强调的是原子性)
  2. 事务隔离级别定义了事务并发操作时的访问规则。
  3. 事务传播行为定义了事务方法在执行时该怎么运用事务。

参考文章:
事务隔离级别:https://www.cnblogs.com/ubuntu1/p/8999403.html
事务传播行为:https://blog.csdn.net/weixin_39625809/article/details/80707695
事务传播行为:https://www.cnblogs.com/softidea/p/5962612.html

原文地址:https://www.cnblogs.com/tanshaoshenghao/p/12184454.html

时间: 2024-11-05 23:24:58

初识事务,事务隔离级别,事务传播行为的相关文章

事务的隔离级别和传播行为

一.事务的隔离级别 1.五种事务的隔离级别 ①读_未提交(read_uncommitted): 会出现脏读.不可重复读.幻读.(隔离级别最低,并发性能高) ②读_已提交(read_committed):会出现不可重复读.幻读.(锁定正在读取的行) ③重复读(repeatable_read):会出现幻读.(锁定所读取的所有行) ④序列化(serializable):保证所有的情况不会发生:(锁表) ⑤默认的隔离级别: 大多数的默认隔离级别是:读已提交(read_commited)如:Sql Ser

事务的隔离级别和传播特性

脏读:当一个事务读取另一个事务未提交的内容,之后由于另一个事务出现了异常回滚了事务,结果造成读取的数据不一致 不可重复读:指一个事务多次读取同一数据,而另一个事务多次对数据进行了修改的操作,这样就导致了第一个事务每次读取的数据不一样, 幻读:当事务一对整张表的数据进行操作时对其进行了新增行,而另一个事务对其进行了删除行,而这时事务一本身对其进行了新增行然而发现并没有对其新增行而产生了幻觉 脏读与不可重复读的区别:脏读是对没有提交的数据进行查询,不可重复读是对已经提交的数据进行的查询 不可重复读与

实战分析:事务的隔离级别和传播属性

什么是事务? 要么全部都要执行,要么就都不执行. 事务所具有的四种特性 原子性,一致性,隔离性,持久性 原子性 个人理解,就是事务执行不可分割,要么全部完成,要么全部拉倒不干. 一致性 关于一致性这个概念我们来举个例子说明吧,假设张三给李四转了100元,那么需要先从张三那边扣除100,然后李四那边增加100,这个转账的过程对于其他事务而言是无法看到的,这种状态始终都在保持一致,这个过程我们称之为一致性. 隔离性 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据是独立的: 持

Spring事务隔离级别和传播特性

在Spring中,声明式事务是用事务参数来定义的.一个事务参数就是对事务策略应该如何应用到某个方法的一段描述,如下图所示一个事务参数共有5个方面组成: 传播行为 事务的第一个方面是传播行为.传播行为定义关于客户端和被调用方法的事务边界.Spring定义了7中传播行为. 传播行为 意义 PROPAGATION_MANDATORY 表示该方法必须运行在一个事务中.如果当前没有事务正在发生,将抛出一个异常 PROPAGATION_NESTED 表示如果当前正有一个事务在进行中,则该方法应当运行在一个嵌

数据库事务隔离级别及传播行为

一.隔离级别: 数据库事务的隔离级别有4个,由低到高依次为Read uncommitted.Read committed.Repeatable read.Serializable,这四个级别可以逐个解决脏读.不可重复读.幻读这几类问题. 1. ISOLATION_READ_UNCOMMITTED:这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据.      这种隔离级别会产生脏读,不可重复读和幻像读.2. ISOLATION_READ_COMMITTED:保证一个事务修改的

数据库事务的四大特性以及事务的隔离级别-与-Spring事务传播机制&隔离级别

本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响. ⑵ 一致性(Consistency) 一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执

事务隔离级别、传播行为及锁机制

1.事务的特性 事务具备以下四个特性,简称ACID属性. 原子性(Atomicity): 事务是一个完整的操作,事务的各步操作都是不可再分的,要么都执行, 要么都不执行. 一致性(Consistency): 当事务完成时,数据必须处于一致的状态. 隔离性(Isolation): 并发事务之间相互独立.隔离,它不应以任何方式依赖于或影响其他事 务. 持久性(Durability): 事务完成后,它对数据库的修改被永久保持. 2. 事务的隔离级别 ① Read uncommitted (读未提交):

数据库事务的隔离级别

数据库事务的隔离级别有4个,由低到高依次为Read uncommitted.Read committed.Repeatable read.Serializable,这四个级别可以逐个解决脏读.不可重复读.幻读这几类问题. √: 可能出现    ×: 不会出现   脏读 不可重复读 幻读 Read uncommitted √ √ √ Read committed × √ √ Repeatable read × × √ Serializable × × × 注意:我们讨论隔离级别的场景,主要是在多个

事务的特性及事务的隔离级别(转)

原文:http://www.cnblogs.com/fjdingsd/p/5273008.html 本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响. ⑵ 一致性(Consi

数据库事务【隔离级别】

为了快速同步数据的需要,我分段执行了两次python脚本,即开启了两个进程同步数据,结果服务器不时报出数据库死锁异常,通过排查代码和数据库日志发现,是由长事务并发引起的.代码中有入账和出账两个方法,里面涉及操作较多,都为其加了事务,抛出异常时可自动回滚,采用数据库(mysql)默认的隔离级别(Repeatable read).提到并发,一般就会想到用同步代码块的方法的处理,但是由于项目是分布式的,共用一个主库,单单在代码加锁是不能保证数据的准确的,那就只能在数据库层面去考虑加锁了.由于数据量暂时