快照隔离与可重复读的关系是什么?

业余草

共 4516字,需浏览 10分钟

 ·

2024-06-13 18:52

来源:juejin.cn/post/7069985361396498462

推荐:https://t.zsxq.com/YRPg5

前言

随着业务迭代,我们会更多地面临分布式环境带来的挑战。

数据库软件或硬件出现问题(写过程中)

应用程序崩溃(多个读写操作中)

网络延迟异常导致数据库链接

并发读写问题

多个客户端之间的竞争条件下出现的异常

事务的引入简化了上述问题的解决,但需要我们正确运用,因此理解事务就变得尤为重要,本文旨在对事务隔离级别简单说明。

相关理论

ACID:Atomicity、Consistency、Isolation、Durability

CAP:Consistency、Availability、Partition tolerance

BASE:Basically Available、Soft state、Eventually consistency

分布式BASE理论:数据一致性模型!

详解 CAP 定理 Consistency(一致性)、 Availability(可用性)、Partition toleranc

聊聊MySQL是如何实现ACID的!

事务隔离级别

未提交读(Read Uncommited)

脏读:一个事务读到了另一个事务未提交的数据

已提交读(Read Commited)

读数据:读已经提交的数据(没有脏读

  • 没有解决不可重复读(read skew, nonrepeatable read) 问题,如下图

1位置Alice查询select balance from accounts where id = 1

2位置Alice认为Account1 + Account2 = 900,但是她总共有1000!

即使两个并发事务全部提交,Alice依然能看到正确的数据,但这“暂时的不一致”(temporary inconsistency)也是不可接受的。

  • 为了解决上述脏读、不可重复读的问题,快照隔离(snapshot isolation)技术被广泛应用于关系型数据库存储引擎。

快照隔离与可重复读(Snapshot Isolation and Repeatable Read)

  • 快照隔离简单来讲就是每个事务都去读取一致的快照(已提交的) ,也就是1的时间节点Alice会查到数据500。
  • 实现快照隔离的方式就是多版本并发控制(MVCC, multi-version concurrency control)。
  • 如果在Read commited级别,MVCC只需要维护(已提交版本、未提交版本)

新增created bydeleted by,记录每个数据快照的创建事务ID与删除事务ID(update可以认为是delete & insert)。

一个小坑:快照隔离在不同的数据库有不同的实现命名,《Designing Data Intensive Applications》原文如下:

In Oracle it is called serializable, and in PostgreSQL and MySQL it is called repeatable read

  • 为了更加清楚地说明,下文就用可重复读(Repeatable Read)级别代替快照隔离

幻读问题

提交读与可重复读对只读(read-only)事务支持我们已经讨论过了,那么对写事务,特别是并发的两个写事务之间会出现什么问题呢?

可以看到,Alice事务和Bob事务分别对shift_id=1234 and on_call=true的数据进行了筛选,并且分别对数据进行了更新,导致最后的数据出现了错误。

幻读问题特征

  1. 使用SELECT语句使用特定条件查询出多条数据;
  2. 依赖上个SELECT语句的结果,决定接下来的操作;
  3. 决定后,写数据并提交事务。

核心在于,B事务插入或删除了,满足A事务SELECT查询条件的数据,导致A事务出现”幻觉“。

串行化(Serializability)

针对上述幻读场景,需要更强的事务隔离级别约束,就是串行化。

串行化级别的实现,取决于各个数据库存储引擎的选型,但主要有以下三种:

  1. 串行化运行
  2. 2PL(Two Phase Locking)机制
  3. 乐观并发控制,例如串行化快照隔离

InnoDB如何解决”幻读“

InnoDB采用2PL机制解决”幻读“,并且在可重复读(RR) 级别实现,具体实现方式为next-key locking

2PL简介

多个并发事务允许读取相同数据,仅当这个数据没有在写入中:

A事务已经读取数据,B事务并发地写入该数据,B必须等A提交或者中断后执行;

A事务已经写入数据,B事务并发的读取该数据,B必须等A提交或者中断后执行。

  • 这里的”数据“包含范围查询出的区间

NEXT-KEY

next-key锁是一种行锁与gap锁的结合,gap锁可以对索引值范围内的行数据进行加锁。

A next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index record.

如果我们拥有一个索引,并且值为10, 11, 13, 20;那么,next-key锁可能的加锁范围如下所示。

(negative infinity, 10]

(10, 11]

(11, 13]

(13, 20]

(20, positive infinity)

结合Bob和Alice的例子,Bob已经读取shift_id=1234 and on_call=true的行数据,那么next-key会对shift_id=1234的范围数据进行加锁,Alice写入必须等待Bob提交完成或者中断,避免幻读问题产生。

参考

  • Designing Data Intensive Applications
  • https://tech.meituan.com/2014/08/20/innodb-lock.html
  • https://dtm.pub/guide/start.html
  • https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

AI 总结

快照隔离(Snapshot Isolation)和可重复读(Repeatable Read)是两种数据库事务隔离级别,它们之间有一些相似性和联系,但也有关键的区别。以下是对这两种隔离级别及其关系的详细解释:

可重复读(Repeatable Read)

可重复读隔离级别确保在一个事务内多次读取同一行数据时,其值始终一致,即使其他事务修改了这行数据。在实现可重复读的过程中,数据库系统通常会采取如下措施:

  • 读取同一行数据时:事务会锁定读取的行,直到事务结束。这防止了其他事务修改或删除这些行。
  • 防止不可重复读:当一个事务读取了一行数据,其他事务不能更新或删除这行数据,直到第一个事务结束。

可重复读的主要问题是幻读(Phantom Read),即在同一个事务内,两次相同的查询结果集不一致,原因是其他事务插入或删除了行。

快照隔离(Snapshot Isolation)

快照隔离是通过多版本并发控制(MVCC)实现的一种隔离级别。在快照隔离下,每个事务在开始时会获取数据的一致性快照,这个快照基于事务开始时的数据状态。这意味着:

  • 事务读取的数据版本一致:在事务执行期间,即使其他事务对数据进行了修改,当前事务读取的数据仍然是事务开始时的状态。
  • 写入冲突检测:如果两个事务尝试修改同一行数据,其中一个事务会被拒绝并回滚,以避免更新丢失。

关系与区别

  1. 相似性

    • 两者都确保了事务内的读取操作一致。
    • 都可以防止不可重复读问题。
  2. 区别

    • 实现方式:可重复读通常通过加锁机制实现,锁定读取的行。而快照隔离通过多版本并发控制实现,事务读取的是开始时的快照。
    • 幻读问题:在可重复读隔离级别下,幻读问题可能依然存在。而快照隔离通过事务快照来避免幻读。
    • 写冲突处理:在快照隔离下,事务之间的写冲突会导致一个事务回滚,而可重复读一般通过锁机制避免写冲突。

最后,留一个问题,InnoDB彻底解决了幻读问题吗?

浏览 42
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报