Mysql:事务隔离性是怎么实现的?

基础

事务

  • 原子性(Atomicity):不可分割,要嘛全部成功,要么全部失败,通过该思想实现了事务回滚机制
  • 一致性(Consistency):说白了就是Mysql指定的一些规则与约束,保持一致性有如下几种机制:
    • 约束(Constraints):如主键约束、外键约束、唯一约束等
    • 事务隔离级别:MySQL提供不同的事务隔离级别,包括读未提交(Read Uncommitted)、读提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。通过合理选择事务隔离级别,可以在并发环境下有效地维护数据的一致性
    • 锁定机制(Locking Mechanisms):MySQL使用锁定机制来控制对数据的并发访问,包括行级锁(Row-Level Locks)、表级锁(Table Locks)等,以确保在并发事务中数据的一致性和完整性。
    • 原子性操作(Atomic Operations):MySQL通过原子性操作确保事务中的所有操作要么全部成功,要么全部失败,从而保持数据的一致性。
  • 持久性(Durability):持久性(Durability)指的是一旦事务被提交,它对数据库的修改应该是永久性的,即使发生系统崩溃或其他故障。
  • 隔离性(Isolation):多个用户并发(同时)访问数据库时, 数据库为每一个用户都开启事物, 为了防止多个事物的操作数据相互干扰, 多个并发事物之间要相互隔离.隔离性通过事务的隔离级别来定义, 并用锁机制来保证写操作的隔离性, MVCC来保证读操作的隔离性.
    • 读未提交(Read Uncommitted):最低的隔离级别,允许事务读取未被其他事务提交的更改。这可能导致“脏读”,即读取到其他事务未提交的数据。
    • 读提交(Read Committed):允许事务读取并仅读取已经被其他事务提交的更改。这个级别可以避免脏读,但仍然可能遇到“不可重复读”的问题,即在同一事务中,多次读取同一数据集合可能会得到不同的结果。
    • 可重复读(Repeatable Read):确保在同一事务中多次读取同一数据集合时,结果是一致的,避免了不可重复读的问题。但是,它可能遇到“幻读”,即当其他事务插入或删除行时,当前事务的后续查询会“看到”新的行。(幻读:老的数据修改不可变,但是新数据造成幻读)(结合MVCC可避免幻读)(Mysql默认隔离级别)
    • 串行化(Serializable):最高的隔离级别,通过强制事务串行执行,避免了脏读、不可重复读和幻读的问题。这提供了最强的一致性保证,但性能开销也最大。

进阶

1、原子性和一致性区别?

原子性: 讲的是操作不可分,把事务看为一个原子,所有的步骤是一个整体,通过该概论,实现了事务回滚机制

一致性: 事务有很多个步骤,如果其中某一步操作违法了规则和约定(比如说唯一性),因为原子性的事务回滚机制存在,N个步骤是一个整体,所以N个步骤的操作都需要回滚。所以一致性更像是出发原子性的一种开关。

总结: 原子性是整体的一种不可分割的概念,通过该概论实现了事务回滚机制;一致性是事务内部各种规则约定的判断,一致性发现错误之后会通知原子性来实现事务回滚。

2、隔离性是怎么实现的?

回答这个问题之前,我们需要知道一下知识点:锁机制、MVCC、间隙锁\快照读与当前读

2.1 隔离性是怎么实现的——锁机制

加锁以防止其他事务同时对该数据对象进行冲突操作。

  • 行级锁、表级锁
    • 行级锁:细粒度锁,允许更高的并发性,不同的事务可以同时操作不同的行。开销大。当并发事务操作的数据分布在不同的行时,行级锁可以显著提升性能。
    • 表级锁:锁定整个数据表,开销小,并发性差,一个事务锁定整个表后,其他事务必须等待该事务完成才能继续操作。
  • 共享锁(S锁)和排他锁(X锁)
    • 共享锁 S:读共享:SELECT查询操作通常使用共享锁
    • 排他锁 X:独占资源::INSERT、UPDATE、DELETE操作通常使用排他锁
  • 意向锁(Intention Locks)
    • 意向锁是管理行级锁和表级锁之间关系的一种机制!意向锁并不会加锁,而是给表打上一个标记,所以他算“表锁”,意图给表中某些行进行加锁 (意向锁就意味着对同表不同行加锁)。
      • 意向共享锁:表示事务有意在表的某些行上加共享锁(S锁)。
      • 意向排他锁:表示事务有意在表的某些行上加排他锁(X锁)。
    • 其实就是对表的不同部位加锁,有点像ConcurrentHashMap分段加锁

对访问统一资源是否兼容?

S锁IS锁IX锁
S锁兼容兼容×
IS锁兼容兼容兼容
IX锁×兼容兼容

为什么IX锁和IX锁兼容?
因为意向锁只是给表打上标记,说明表内某些行加了X锁,如果IX锁是针对同一行,那就会出发X锁判断机制。

为什么需要意向锁?
因为意向锁代表了表中某行加锁了,这样就可以避免表锁冲突!

2.2 隔离性是怎么实现的——MVCC
  • 数据的版本控制

    • 创建版本号:生成该版本的事务ID
    • 删除版本号:删除该版本的事务ID
  • 读取操作快照读

    • A事务开始时,Mysql会为这个事务分配一个ID号,即事务ID(TXID)
    • A事务开始时,事务会获取一个快照,存储的是开始时间点前所有已提交的数据版本(就是所有已经提交的事务ID号)
    • A事务有了自己的ID,A事务又有了快照,就可以通过比对ID号来判断那个版本对自己可以见
  • 写入操作当前读

    • 当事务需要更新某一行数据时,它会创建一个新的版本,并更新创建版本号字段为自己的TXID。同时,将旧版本的删除版本号字段设为当前事务的TXID,表示旧版本对新事务不可见。
  • 提交和回滚

    • 事务提交后,它生成的新版本会对其他事务可见。
    • 如果事务回滚,则丢弃它生成的新版本,数据的版本链条保持不变。
  • 版本链
    在MVCC机制下,每次对数据库中的一行数据进行更新操作时,数据库并不会立即覆盖掉这行数据的旧版本,而是创建一个新的版本,将旧版本保留在数据库中。这些版本按照时间顺序链接在一起,形成一个版本链。

    • 版本存储的位置:MySQL的InnoDB存储引擎:会使用UNDO日志来存储旧版本的数据。UNDO日志是一个回滚日志,它记录了事务在执行时对数据所做的更改。
    • 版本的清除
      • 垃圾回收(Garbage Collection):当不再有任何活动事务需要访问某个版本时,数据库会将这些旧版本标记为垃圾,并进行回收。垃圾回收的时机通常是在所有事务都完成后,特别是当所有事务都已经提交或回滚,且不再需要访问这些旧版本的数据。
      • Purge 过程
    • 何时版本被清除
      • 事务提交后
      • Purge 机制

版本链中提到的UNDO是什么?

UNDO日志是数据库管理系统中用于支持事务回滚和多版本并发控制(MVCC)的重要机制之一。它记录了事务在执行过程中对数据所做的更改,特别是原始数据的备份,以便在需要时恢复数据到事务执行之前的状态。

UNDO日志的功能与作用

  1. 事务回滚:
    • 当一个事务正在执行时,可能会遇到某些问题导致事务需要回滚,例如违反了约束条件、出现死锁,或者用户主动中止事务。在这种情况下,数据库需要撤销事务所做的所有更改,将数据恢复到事务开始前的状态。
  2. 支持MVCC
    • UNDO日志在MVCC机制下也起着至关重要的作用。它记录了数据的历史版本,使得数据库能够在并发事务中为不同事务提供一致的历史视图。
  3. 崩溃恢复
    • 在数据库系统发生崩溃时,UNDO日志也用于崩溃恢复。数据库系统会利用UNDO日志将所有未提交的事务进行回滚,确保系统恢复到一个一致的状态。

UNDO日志的结构与存储

  1. 日志内容:
    • 事务ID:指示哪个事务进行了该操作
    • 操作类型:例如INSERT、UPDATE、DELETE等操作
    • 旧数据值:在执行写操作之前,记录下数据的原始值。
    • 行指针:指向被修改的具体数据行。

问题1: MVCC的快照存储的是什么数据?
答: 快照存储的是事务开始时所有的数据版本(创建版本号、删除版本号)

 
问题2: 两个事务开始时间相差无几,拿得到的快照大同小异,如果操作同一条数据,都产生了新版本,这两个事务提交时,又是怎么处理的?
答: 并发场景主要看事务隔离级别以及并发冲突处理机制
① 读操作:如果是两个时候都是读操作,那么各自读取独立的数据版本,互补干扰。
② 写操作:那就要看不同事务级别的处理机制,如下:

乐观并发控制:快照只是可以看到什么数据,最终事务要提交时,才会判断是否并发冲突
乐观并发控制:在事务执行过程中加锁,防止其他事务同时修改同一数据。如果一个事务正在修改某行数据,其他事务将被阻塞,直到第一个事务提交或回滚。

  • 读已提交(Read Committed):
    在这个隔离级别下,每次读取数据时,事务都会看到其他已提交事务的最新数据版本。如果两个事务几乎同时开始,并且都对同一条数据进行了修改,通常第一个提交的事务会成功,而第二个提交的事务会在提交时检测到冲突。第二个事务在提交时会检查自己基于的快照版本是否仍然是最新的。如果不是(因为第一个事务已经提交了修改),第二个事务的提交会失败,并引发回滚或需要重新执行。
  • 可重复读(Repeatable Read):
    在这个隔离级别下,事务会一直看到自己开始时的快照数据,无论其他事务是否已经提交。两个事务如果几乎同时开始,并且都修改了同一条数据,第一个提交的事务会成功,第二个事务在提交时同样会检测到冲突(即它基于的快照版本已经过时),导致提交失败,必须回滚。
  • 可串行化(Serializable):
    这是最高的隔离级别,保证事务仿佛是串行执行的。在这种情况下,数据库系统会强制所有并发事务看起来是一个接一个地执行的。如果两个事务试图同时修改同一行数据,系统可能会使其中一个事务等待,直到另一个事务完成为止。这样可以确保不会产生冲突,虽然这会降低系统的并发性。

问题3: MVCC与加锁之间的关系?怎办么配合工作的?
答: MVCC快照是为了让事务可以安心的读取了数据,而不用担心被别的版本扰乱,但如果事务AB同时修改一行数据,即便他们各自操作快照中的数据,在提交时人任然需要加锁。 快照先于加锁加锁发生在写操作时。

2.3 隔离性是怎么实现的——间隙锁
2.3.1 间隙锁的定义

间隙锁是加在索引记录之间的“间隙”上的一种锁。这种锁不会锁定具体的数据行,而是锁定两个索引记录之间的区域(即所谓的“间隙”)。如果你对表中索引列的某个范围进行查询(例如使用BETWEEN或范围扫描查询),间隙锁会锁住范围内的所有“间隙”,防止其他事务在这个范围内插入新的记录。

2.3.2 间隙锁的目的

主要目的是防止“幻读”现象,即一个事务在两次读取之间发现了“新”插入的记录。如果不加间隙锁,另一个事务可能会在同一个间隙内插入新记录,这样当前事务再读取时就会看到这些新插入的记录,导致幻读。在高隔离级别下,通过锁定间隙,InnoDB确保没有其他事务能够在这个间隙内插入新的记录,从而避免幻读,保证一致性。

查询时索引覆盖也是要加锁避免幻读的啊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值