MySQL的MVCC

一、定义

MVCC是MySQL为了提高数据库并发操作提供的一种多版本并发控制机制。MVCC可以在大多情况避免加锁,实现了非阻塞读、非阻塞写,因此开销更小。MVCC支持的事务隔离级别有:读已提交、可重复读

二、原理

每次对数据库表里的数据进行修改的时候,都会生成一条undo_log日志

每个行记录都有2个隐藏字段:trx_id和roll_pointer

每当有个事务对该行记录进行修改的时候,都会把这个事务的事务id赋值给这个行记录的trx_id。而roll_pointer负责指向undo_log中旧版本的数据。

通过这个机制,可以找到这条行记录修改前的数据。

例子:

假设有5个事务,事务1是对记录id为1的name修改为aa,事务2是对记录id为1的name修改为bb,事务3是对记录id为1的name修改为cc,事务4是查询记录id为1的内容,事务5是查询记录id为1的内容。

执行过程是:

事务1在对记录id1进行修改前,先生成一条undo_log,然后对该记录进行修改,trx_id修改为事务1,roll_pointer指向刚才生成的undo_log。

事务2同事务1相同,会修改行记录指向上个版本的数据。

事务3同事务1相同,会修改行记录指向上个版本的数据。

到现在为止,形成了一个undo_log版本链,事务3(未提交)所修改的行记录roll_pointer指向事务2所修改的行记录,事务2(未提交)修改的行记录roll_pointer指向事务1所修改的行记录,事务1(已提交)所修改的行记录roll_pointer指向一开始未作修改的行记录。

在读已提交的隔离级别下,当事务4要去查询id1的数据时,会先生成一个read_view读视图,读视图里面记录了undo_log版本链里面的一些统计信息,主要的信息是:m_ids记录当前数据库中活跃事务的事务id列表(活跃事务指已启动但未提交的事务)、min_trx_id记录m_ids中最小的事务id、max_trx_id记录m_ids中最大事务id再加1。其中min_trx_id之前是已提交事务,max_trx_id(包含本身)之后是还未开启的事务。

这里要注意,在读已提交隔离级别中,每次做数据查询都会生成一个读视图,这样会导致每次查询到的相同的记录的值会不一样。事务4在查询时,会先获取m_ids列表事务2、事务3,找到比min_trx_id小的的最大值,这里是会返回事务1对应的undo_log数据即aa。在这个事务里面再执行一次查询,会生成一个新的读视图。

在可重复读的隔离级别下,整个事务都会用同一个读视图,所以接下来当事务5去查询记录id1的内容,会创建一个读视图,然后获取m_ids列表的数据,这时是事务2、事务3,找到比min_trx_id更小的最大事务id即事务1,返回对应的undo_log数据即aa。在这个事务再执行一次查询,依然会使用该读视图,所以可以确保每次查询的记录值相同,解决不可重复读问题,但还是没有解决幻读问题

可重复读为什么没有解决幻读问题?

若某个事务仅仅进行范围查询且加上了间隙锁或者临键锁则可以解决幻读问题。但是若是以下复杂场景,依然无法解决幻读问题:

当在事务A里面查询时,会先生成读视图,然后从undo_log找到对应数据返回(快照读),接着若在这个事务A过程中,有其他事务B也在往这个表插入数据并提交完成,然后事务A执行update操作,该update操作的条件<=(临键锁)覆盖(锁住)了事务B的数据,这时候会进行当前读操作,即不读取undo_log版本链的数据,直接读取数据库中的数据,当修改完毕后,由于前面的update操作覆盖了其他事务的数据,所以再进行查询会重新生成读视图,这时候再去调用相同的查询条件,会发现查询出来的数目不相同,出现幻读现象。若update操作的条件没有覆盖(锁住)其他事务的数据,则不会重新生成读视图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值