三分钟了解MVCC(InnoDB如何实现可重复读和读已提交)

快照读和当前读

快照读

快照读是指读取数据时不是读取最新版本的数据,而是基于历史版本读取的一个快照信息(mysql读取undo log历史版本) ,

快照读可以使普通的SELECT 读取数据时不用对表数据进行加锁

当前读

当前读是读取的数据库最新的数据,当前读和快照读不同,因为要读取最新的数据而且要保证事务的隔离性,所以当前读是需要对数据进行加锁的

(update、delete、insert、select ....lock in share mode、select for update)

 

MVCC如何解决幻读?

快照读下,通过Read view的方式解决了幻读,本文主要介绍快照读下的的幻读解决方式

当前读下,需要使用间隙锁来解决幻读,但本质上当前读就是为了查最新数据

如 select * from xxx where id > 1 for update

 

Read view是什么?

InnoDB的快照读并非创建数据的完整备份,而是创建了一份事务id相关的数据快照,结合undo_log来实现整体数据的快照读

read view主要储存了下列4项数据的快照

trx_ids: 当前系统活跃(未提交)事务版本号集合。

low_limit_id: 创建当前read view 时当前系统最大事务版本号+1。

为什么不是当前事务版本号+1:事务开始时刻为当前事务版本号+1,但读已提交级别的后续查询会创建新的readview,所以实际储存的是最大事务版本号+1

up_limit_id: 创建当前read view 时“系统正处于活跃事务最小版本号”

creator_trx_id: 创建当前read view的事务版本号;

 

InnoDB如何实现可重复读和读已提交?

1)数据库已存记录

trx_id

数据

undolog

0

id = 1; name = cjd1

 

0

id = 2; name = cjd2

 

 

2)trx_id=2 修改数据id=1的数据 name=cjd11

trx_id

数据

undolog

 

trx_id

数据

undolog

2

id = 1; name = cjd11

0xxxxxxx

0

id = 1; name = cjd1

 

0

id = 2; name = cjd2

 

 

 

 

 

 

读已提交场景

3)trx_id=3 开启查询,创建readview

trx_ids

low_limit_id

up_limit_id

creator_trx_id

2,3

2

4

3

 

此时数据库数据为

trx_id

数据

undolog

 

trx_id

数据

undolog

2

id = 1; name = cjd11

0xxxxxxx

0

id = 1; name = cjd1

 

0

id = 2; name = cjd2

 

 

 

 

 

 

trx_id = 2

>= low_limit_id(处于活跃的最小版本号) 且

< up_limit_id(当前系统最大事务版本号+1)且

!=creator_trx_id(当前事务版本号) 但

in trx_ids(正在活跃的事务版本号内)

 

故此数据不可见,根据undolog指针找到上一条记录trx_id=0 < low_limit_id,故数据可见

故该查询最终得到的数据为

trx_id

数据

undolog

 

trx_id

数据

undolog

2

id = 1; name = cjd11

0xxxxxxx

0

id = 1; name = cjd1

 

0

id = 2; name = cjd2

 

 

 

 

 

 

4)trx_id=2 新增记录id =3; trx_id=4新增记录id=4

trx_id

数据

undolog

 

trx_id

数据

undolog

2

id = 1; name = cjd11

0xxxxxxx

0

id = 1; name = cjd1

 

0

id = 2; name = cjd2

 

 

 

 

 

2

id = 3; name = cjd3

 

 

 

 

 

4

id = 4; name = cjd4

 

 

 

 

 

 

5)trx_id=3 开启查询,创建readview

trx_ids

low_limit_id

up_limit_id

creator_trx_id

2,3,4

2

5

3

新增的id=3与id=4,因为事务版本号处于活跃,故都对该次查询不可见

故该查询最终得到的数据为

trx_id

数据

undolog

 

trx_id

数据

undolog

2

id = 1; name = cjd11

0xxxxxxx

0

id = 1; name = cjd1

 

0

id = 2; name = cjd2

 

 

 

 

 

2

id = 3; name = cjd3

 

 

 

 

 

4

id = 4; name = cjd4

 

 

 

 

 

 

6)trx_id=4 修改id=4数据为name=cjd41,并提交事务,trx_id=3创建数据name=cjd5

trx_id

数据

undolog

 

trx_id

数据

undolog

2

id = 1; name = cjd11

0xxxxxxx

0

id = 1; name = cjd1

 

0

id = 2; name = cjd2

 

 

 

 

 

2

id = 3; name = cjd3

 

 

 

 

 

4

id = 4; name = cjd41

0xxxxxxx

4

id = 4; name = cjd4

 

3

id = 5; name = cjd5

 

 

 

 

 

 

7)trx_id=3 开启查询,创建readview

trx_ids

low_limit_id

up_limit_id

creator_trx_id

2,3

2

5

3

 

事务4提交后,数据name=cjd41 对事务3可见,name=cjd5事务号为创建者自身也可见,故最终查询得到的数据为

trx_id

数据

undolog

 

trx_id

数据

undolog

2

id = 1; name = cjd11

0xxxxxxx

0

id = 1; name = cjd1

 

0

id = 2; name = cjd2

 

 

 

 

 

2

id = 3; name = cjd3

 

 

 

 

 

4

id = 4; name = cjd41

0xxxxxxx

4

id = 4; name = cjd4

 

3

id = 5; name = cjd5

 

 

 

 

 

 

可重复读场景

3)可重复读场景下,无论第几次查询均使用事务开启时创建的read view,但可以读到后续自身事务创建的数据

trx_ids

low_limit_id

up_limit_id

creator_trx_id

2,3

2

4

3

故可重复读得到的查询结果为

trx_id

数据

undolog

 

trx_id

数据

undolog

2

id = 1; name = cjd11

0xxxxxxx

0

id = 1; name = cjd1

 

0

id = 2; name = cjd2

 

 

 

 

 

2

id = 3; name = cjd3

 

 

 

 

 

4

id = 4; name = cjd41

0xxxxxxx

4

id = 4; name = cjd4

 

3

id = 5; name = cjd5

 

 

 

 

 

 

读已提交每次查询创建新的read view,可重复读使用的第一次创建的read view

这也是为什么可重复读能解决幻读,而读已提交不能解决幻读的原因

 

 

 

MVCC(多版本并发控制)是一种用于解决并发写冲突的机制。在MVCC中,数据库会为每个事务创建一个快照,该快照是事务开始时数据库中数据的一个副本。因此,在可重复读隔离级别下,MVCC通过使用快照来解决可重复读的问题。 在可重复读中,多个事务同时取同一行数据时,MVCC会根据每个事务开始时的快照来提供一致性视图。这意味着,如果一个事务正在取数据,并且另一个事务正在修改相同的数据,那么取操作将返回事务开始时的数据快照,而不会受到其他事务的修改的影响。 具体来说,MVCC通过在每个数据行中保存多个版本的数据来实现可重复读。当一个事务开始时,它会创建一个快照,并且只能看到在该快照之前已经提交的数据版本。如果其他事务正在修改相同的数据行,那么这些修改将被保存在新的数据版本中,而不影响当前事务的取操作。 因此,MVCC通过使用快照和当前的组合来实现可重复读快照提供了一致性的数据视图,而当前则用于取最新的数据,并在写操作之前取数据。 总之,MVCC通过使用快照和多个数据版本来解决可重复读的问题,确保事务在取数据时不会受到其他并发事务的修改的干扰。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [MySQL(五)—MVCC解决可重复读的幻了吗?](https://blog.csdn.net/shang_0122/article/details/120298810)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [详解MySQL是如何解决幻的](https://download.csdn.net/download/weixin_38730767/13699659)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值