MYSQL事务与MVCC

Mysql事务的基本要素(ACID)

A:原子性:要么全部成功,要么全部失败

C:一致性:事务开始前和结束后,数据库的完整性约束没有被破坏(保证数据的正确性)
I:隔离性:一个事务的执行影响另一个事务的运行

D:持久性:更新后的数据会永久的留存在数据库中

所有要素最终都是为了数据一致性

事务并发产生的问题

多事务并发有三种异常情况,违反了隔离性

  1. 脏读:一个事务读取到了另一个事务未提交的数据
  2. 不可重复读:一个事务中同一查询语句执行多次,存在一个记录却有两个不同的内容(一个事务做查询操作,另一个事务做更新操作) [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9sFKat5Q-1672131122002)(https://secure2.wostatic.cn/static/hahJ1s8CWfjc17RS78NDqi/image.png?auth_key=1672130992-5yqaLQjdc89F9p4BTztdVq-0-fbd3e3401a0f2f2540dfbd2d4b3830e4)]  [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-phbQcSW0-1672131201314)(https://secure2.wostatic.cn/static/hahJ1s8CWfjc17RS78NDqi/image.png?auth_key=1672130992-5yqaLQjdc89F9p4BTztdVq-0-fbd3e3401a0f2f2540dfbd2d4b3830e4)] 3. 第二类更新丢失(两个事务对同一条数据都在做更新操作)
    在这里插入图片描述

4.幻读:一个事务中同一查询语句的记录条数不一致(A事务做查询操作,B事务做新增操作)
在这里插入图片描述

在这里插入图片描述

幻读不不可重复读的区别(一个是由更新导致,一个是由新增或删除导致)

数据库是如何保证事务的隔离性的呢?

数据库可以通过加锁来保证事务的隔离性。但是加锁后性能问题影响过大。MYSQL使用MVCC解决脏读,不可重复读,幻读问题

MySQL的锁类型

SQL标准定义的隔离级别

  1. 未提交读:
  2. 已提交读:解决脏读问题
  3. 可重复读:解决不可重复度问题(mysql默认隔离级别)
  4. 序列化:解决幻读问题

MYSQL通过锁和MVCC实现以上隔离级别

MVCC原理(多版本并发控制

MVCC是在并发访问数据库时,通过对数据做多版本管理,避免因为写数据时要加写锁而阻塞读取数据的请求,造成写数据时无法读取数据的问题。。MVCC解决的更多的是如何读的问题。并不能取代数据库的锁和数据不能和数据库中的锁混为一谈。当多个事务对数据资源做出并发修改时还是需要锁的控制

MVCC核心概念

了解MVCC之前我们需要知道以下概念

1. 事务版本号
每次事务开启前都会从数据库获得一个自增长的事务ID,可以从事务ID判断事务的执行先后顺序
2. 表格中的隐藏列
对于InnoDB存储引擎,每一行记录都有两个隐藏列**trx_id**(事务版本号)、**roll_pointer**(回滚指针,roll_pointer存储的是旧数据的地址),如果表中没有主键和非NULL唯一键时,则还会有第三个隐藏的主键列**row_id**。
3. Undo log
用于记录数据被修改前的信息

作用:
  - 当事务回滚的时候通过此日志还原数据
  - 通过读取undo log的历史版本数据可以实现**不同事务版本号都拥有自己独立的快照数据版本。**
4.版本链
多个事务并行操作某一行数据时,不同事务对该行数据的修改会产生多个版本,然后通过回滚指针(roll_pointer),连成一个链表,这个链表就称为**版本链**

在这里插入图片描述

详细介绍:

在这里插入图片描述

5. ReadView
它就是事务执行SQL语句时,产生的读视图。实际上在innodb中,每个SQL语句执行前都会得到一个Read View。它主要是用来做可见性判断的,即判断当前事务可见哪个版本的数据

在innodb 中每个事务开启后都会得到一个read_view。副本主要保存了当前数据库系统中正处于活跃(没有commit)的事务的ID号

**Read view 的几个重要属性:**
trx_ids: 当前系统活跃(未提交)事务版本号集合
low_limit_id: 创建当前read view 时“当前系统最大事务版本号+1”
up_limit_id: 创建当前read view 时“系统正处于活跃事务最小版本号”
creator_trx_id: 创建当前read view的事务版本号
**Read view**可见性判断

1. 若事务ID < up_limit_id  || 事务ID=creator_trx_id 则显示

    表明read view产生后,事务就已经commit
2. 若事务ID ≥ low_limit_id 则不显示

    表明read view产生后事务才开始。不能显示
3. up_limit_id≤事务ID<low_limit_id则需要和trx_ids里的数据进行匹配
    1. 如果在trx_ids 集合中则不显示

        表明read view产生后,事务ID的这个事务还没commit
    2. 如果不在trx_ids 集合中则显示

        read view产生的时候事务已经commit了

通过ReadView、版本链、undo log来返回快照读数据

核心:判断版本链中的那个版本是当前事务是否可见来返回数据
在这里插入图片描述

MVCC实现已提交读

RC级别下事务开启后,在每次执行快照读时生成ReadView,根据**Read view可见性判断**和**版本链undo log**返回结果

MVCC实现可重复读

RR级别下事务开启后,只在第一次快照读时生成ReadView,根据**Read view可见性判断**和**版本链undo log**返回结果

快照读和当前读

快照读:只有select单纯的读取操作,会在读取的时候生成ReadView快照数据

当前读:读取的是最新版本,并且对数据加锁,会阻塞其他操作修改记录。比如select……lock in share mod(加共享锁,又称S锁),select……for update(加排它锁,又称X锁),update,delete,insert这类操作都是当前读

MVCC 在RR级别下 可以解决部分幻读

MVCC 在RR级别下 可以解决部分幻读, 但不能完全解决.

Mysql官方给出的幻读解释是:

只要在一个事务中,第二次select多出了row就算幻读。

1. a事务先select,b事务 insert确实会加一个gap锁,但是如果b事务commit,这个gap锁就会释放(释放后a事务可以随意dml操作)。
2. a事务再select出来的结果在MVCC下还和第一次select一样;这一步没有出现幻读。
3. 接着a事务不加条件地update,这个update会作用在所有行上(b事务已经提交,包括b事务新加的)。
4. a事务再次 select就会出现b事务中的新行(幻读出现),并且这个新行已经被 update修改了。

参考链接:https://zhuanlan.zhihu.com/p/421769708
https://zhuanlan.zhihu.com/p/52977862

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值