mysql mvcc实例讲解_MySQL中的MVCC

MySQL中的MVCC

MVCC的概念

MVCC: Multi-Version Concurrency Control,即多版本并发控制.

是乐观锁的一种实现方式.

并发事务存在的问题:

更新丢失(Lost Update):多个事务同时更新同一行时,最后的更新会覆盖之前的更新。

脏读(Dirty Reads):一个事务对记录的未提交修改被其他事务读取到。

不可重复读(Non-Repeatable Reads):一个事务内多次查询相同记录结果不一致。

幻读(Phantom Reads):一个事务重新查询之前检索过的数据,发现出现新的数据。

解决:

加读写锁。

一致性快照读(MVCC)。

特点

用来提高数据库高并发场景下的吞吐性能。

MySQL中InnoDB引擎支持MVCC。

比加行锁效率高,开销低。

在读已提交(Read Committed)和可重复读(Repeatable Read)隔离级别下起作用。

可以基于乐观锁和悲观锁实现。

使用行级锁(row_level_lock),而非行锁(innodb_row_lock).

同一个事务能够看到数据一致的视图.

事务开始的时间不同,看到相同表的数据可能不同.

基本原理

通过保留某个时间点的快照实现的.

基本特征

每行数据都存在一个版本,每次数据更新时都更新该版本.

修改数据时复制当前版本的数据进行修改,各个事务之间互不影响.

保存时比较版本号,成功(commit)则覆盖原记录,失败则放弃(rollback).

InnoDB存储引擎MVCC实现策略

细节:

每一行保存两个隐藏列:当前行创建时版本号和删除时版本号.

版本号是系统版本号,每开始一个新事务,系统版本号自增.而事务的版本号为事务开始时的系统版本号.

每个事务有自己的版本号.

MVCC下的InnoDB的增删改查

插入数据

设记录的版本号为当前事务的版本号。

向表中插入数据。

将create version设置为当前事务的版本号,delete version为空。

更新操作

将旧的记录标记为已删除,delete version为当前事务版本号。

插入一行新的记录,create version为当前事务版本号,delete version为当前版本号。

删除操作

将待删除的行的delete version设置为当前事务版本号。

查询操作

记录需满足两个条件:

delete version为空或者设置的版本号大于当前事务的版本号(即:删除操作发生在当前事务之后)

create version小于等于当前事务版本号(即:记录创建在当前事务之前)

注:

MVCC只适用于MySQL中的读已提交(Read Committed)和可重复读(Repeatable Read)。

Read uncommitted存在脏读,即:读到未提交事务的数据行。

串行化是对表加锁。

InnoDB MVCC 实现原理

实现方式:

每一行记录都有两个隐藏列:DATA_TRX_ID和DATA_ROLL_PTR。(若没有主键,则还有一个隐藏主键)

DATA_TRX_ID:记录最近更新这条记录的事务ID(6字节)

DATA_ROLL_PTR:指向该行回滚段的指针,通过指针找到之前版本,通过链表形式组织(7字节)

DB_ROW_ID:行标识(隐藏单增ID),没有主键时主动生成(6字节)

多事务并发操作数据

特征:

不同事务对同一行的更新操作产生多个版本。

通过回滚指针将这些版本链接成一条Undo Log链。

更新操作流程:

将待操作的行加排他锁。

将该行原本的值拷贝到Undo Log中,DB_TRX_ID和DB_ROLL_PTR保持不变。(形成历史版本)

修改该行的值,更新该行的DATA_TRX_ID为当前操作事务的事务ID,将DATA_ROLL_PTR指向第二步拷贝到Undo Log链中的旧版本记录。(通过DB_ROLL_PTR可以找到历史记录)

记录Redo Log,包括Undo Log中的修改。

INSERT操作:产生新的记录,其DATA_TRX_ID为当前插入记录的事务ID。

DELETE操作:软删除,将DATA_TRX_ID记录下删除该记录的事务ID,真正删除操作在事务提交时完成。

一致性读的实现

RU隔离级别下 ==> 直接读取版本的最新记录。

SERIALIZABLE隔离级别 ==> 通过加锁互斥访问数据实现。

RC和RR隔离级别 ==> 使用版本链(ReadView,可读视图)

RR下的ReadView生成

特点:

每个事务首次执行SELECT语句时,会将当前系统所有活跃事务拷贝到一个列表中生成ReadView。

每个事务后续的SELECT操作复用其之前生成的ReadView。

UPDATE,DELETE,INSERT对一致性读snapshot无影响。

示例:事务A,B同时操作同一行数据

若事务A的第一个SELECT在事务B提交之前进行,则即使事务B修改记录后先于事务A进行提交,事务A后续的SELECT操作也无法读到事务B修改后的数据。

若事务A的第一个SELECT在事务B修改数据并提交事务之后,则事务A能读到事务B的修改。

RC下的ReadView生成

特点:

每次SELECT执行,都会重新将当前系统中的所有活跃事务拷贝到一个列表中生成ReadView。

ReadView的组成:(当前活跃事务ID列表,称为m_ids)

最小值为up_limit_id:最先开始的事务。

最大值为low_limit_id:最后开始的事务。

ID越小,事务开始的越早;ID越大,事务开始的越迟。

若被访问版本的trx_id小于up_limit_id == > 生成该版本的事务在ReadView生成前就已提交 == > 该版本可以被当前事务访问。

若被访问版本的trx_id大于low_limit_id == > 生成该版本的事务在ReadView生成之后才提交 == > 该版本不可被当前事务访问 == > 通过Undo Log找到之前的版本重新判断。

若被访问的版本在up_limit_id和low_limit_id之间 == > 需要判断trix_id是否在m_ids中存在 == > 若存在,则生成该版本的事务还在活跃,则该版本不可访问,可由Undo Log找到之前的版本进行重新判断;若不存在,则创建ReadView时该版本对应的事务已提交,可以访问该版本。

找到记录后,还要判断delete_flag是否为true,若为true,则该记录已被删除,不返回;若为false,则记录可以返回。

注:对于ID较大的事务较ID较小的事务先提交的情况,即事务发生晚但提交的早

RC的本质:每一条SELECT都可以看到其他已经提交的事务对数据的修改,只要事务提交,其结果都可见,与事务开始的先后顺序无关。

RR的本质:第一条SELECT生成ReadView前,已经提交的事务的修改可见。

参考:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值