mysql mvcc update_MySql MVCC机制

Multiversion concurrency control 多版本并发控制

并发访问(读或者写)数据库时,对正在事务内处理的数据做多版本的管理,用来避免由于写操作的堵塞,而引发读操作失败的并发问题。

MySql默认采用RR级别允许幻读,但是不允许可重复度和脏读

Sample

create table `test` (

`id` int (11),

`test_id` int (11)

);

insert into `test` (`id`, `test_id`) values('1','18');

insert into `test` (`id`, `test_id`) values('4','8');

insert into `test` (`id`, `test_id`) values('7','4');

insert into `test` (`id`, `test_id`) values('10','1234');

set autocommit=0;

用户1

begin;

-- 更新 id 为 1 的数据

UPDATE test SET test_id = 20 WHERE id = 1;

SELECT * FROM test WHERE id = 1;

+------+---------+

| id | test_id |

+------+---------+

| 1 | 20 |

+------+---------+

用户2

begin;

--查询 id 为 1 的数据

SELECT * FROM test WHERE id = 1;

+------+---------+

| id | test_id |

+------+---------+

| 1 | 18 |

+------+---------+

通过结果说明:我们可以在一个事务未进行 commit/rollback操作之前,另一个事务仍然可以读取到数据库中的数据,只不过是读取到的是其他事务未改变之前的数据。此处是利用了MVCC多数据做了多版本处理,读取的数据来源于快照。

什么是MVCC

MVCC,Multi-Version Concurrency Control,多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问;在编程语言中实现事务内存。

如果有人从数据库中读数据的同时,有另外的人写入数据,有可能读数据的人会看到『半写』或者不一致的数据。有很多种方法来解决这个问题:

最简单的办法:通过加锁,让所有的读者等待写者工作完成,但是这样效率会很差。

MVCC方法:每个连接到数据库的读者,在某个瞬间看到的是数据库的一个快照,写者写操作造成的变化在写操作完成之前对于读者都是不可见的。

当一个 MVCC 数据库需要更新或者新增一条数据记录的时候,它不会直接用新数据覆盖旧数据,而是将旧数据标记为过时(obsolete)并在别处增加新版本的数据。这样就会有存储多个版本的数据,但是只有一个是最新的。这种方式允许读者读取在他读之前已经存在的数据,即使这些在读的过程中半路被别人修改、删除了,也对先前正在读的用户没有影响。 需要付出的代价仅仅是需要系统周期性整理(sweep through)以真实删除老的、过时的数据。

MVCC 并发控制下的读事务一般使用时间戳或者事务 ID去标记当前读的数据库的状态(版本)

读取数据时,读、写事务相互隔离,不需要加锁。

读写并存的时候,写操作会根据目前数据库的状态,创建一个新版本,并发的读则依旧访问旧版本的数据

MySQL中对于 MVCC 的逻辑实现

MySql MVCC逻辑插入

在MySQL中建表时,每个表都会有三列隐藏记录,其中和MVCC有关系的有两列

数据行的版本号 (DB_TRX_ID)

删除版本号 (DB_ROLL_PT)

25f992b37c5977101be0cdceb61a3b71.png

在插入数据的时候,假设系统的全局事务ID从1开始,以下SQL语句执行分析参考注释信息:

begin;-- 获取到全局事务ID

insert into `test` (`id`, `test_id`) values('5','68');

insert into `test` (`id`, `test_id`) values('6','78');

commit;-- 提交事务

当执行完以上SQL语句之后,表格中的内容会变成:

5122f278fe646b46a82a25be61826e46.png

可以看到,插入的过程中会把全局事务ID记录到列 DB_TRX_ID 中去

MySql MVCC逻辑删除

对上述表格做删除逻辑,执行以下SQL语句(假设获取到的事务逻辑ID为 3)

begin;--获得全局事务ID = 3

delete test where id = 6;

commit;

执行完上述SQL之后数据并没有被真正删除,而是对删除版本号做改变,如下所示:

14c6d710325d1c8034daf33f494f7af0.png

MySql MVCC逻辑更新

修改逻辑和删除逻辑有点相似,修改数据的时候 会先复制一条当前记录行数据,同时标记这条数据的数据行版本号为当前事务版本号,最后把原来的数据行的删除版本号标记为当前是事务版本号。

begin;-- 获取全局系统事务ID 假设为 10

update test set test_id = 22 where id = 5;

commit;

执行后表格实际数据应该是:

d768988a6df06cd66fc7e224fb330db5.png

MySql MVCC逻辑查询

数据查询规则如下:

查找数据行版本号早于当前事务版本号的数据行记录

查找删除版本号要么为NULL,要么大于当前事务版本号的记录

根据上述规则,我们继续以上张表格为例,对此做查询操作

begin;-- 假设拿到的系统事务ID为 12

select * from test;

commit;

执行结果应该是:

5f131e1b93d4c987d56c6f64380921f0.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值