mysql-MVCC

MVCC,全称Multi-Version Concurrency Control  解决了不可重复读问题,但是会有幻读问题。

什么是不可重复读问题?

        事务1 读取id = 1 的数据 ,事务2修改了id为1的数据并且提交,事务1又读了一次id=1的数据,两次重复读取同一条的数据不一致,这个叫不可重复读,MVCC能使两次读取的数据一致。

MVCC如何解决的?

        MVCC会将每次事务修改的数据记录下来形成undo log,log上有事务id,当一个事务第一次读取数据的时候,会生成一个Read View 读视图,读视图中会有当前事务第一次读数据的事务id,并且下次读的时候,会根据事务id来查询对应的undo log。

MVCC数据结构与原理

        关键字:undolog , read view ,隐藏字段        

        undolog

                undolog被称之为回滚日志,表示在进行insert,delete,update操作的时候产生的方便回滚的日志,用于保证数据的原子性。

​                当进行insert操作的时候,产生的undolog只在事务回滚的时候需要,并且在事务提交之后可以被立刻丢弃

        隐藏字段:

                数据库的每行数据有一些隐藏字段,下面说跟事务有关系的三个字段

                DB_TRX_ID

​                6字节,最近修改事务id,记录创建这条记录或者最后一次修改该记录的事务id

​                DB_ROLL_PTR

​                7字节,回滚指针,指向这条记录的上一个版本,用于配合undolog,指向上一个旧版本

​                DB_ROW_JD

read view

​        Read View是事务进行快照读操作的时候生产的读视图,在该事务执行快照读的那一刻,会生成一个数据系统当前的快照,记录并维护系统当前活跃事务的id,事务的id值是递增的。

​        其实Read View的最大作用是用来做可见性判断的,也就是说当某个事务在执行快照读的时候,对该记录创建一个Read View的视图,把它当作条件去判断当前事务能够看到哪个版本的数据,有可能读取到的是最新的数据,也有可能读取的是当前行记录的undolog中某个版本的数据

​      ​        

什么是幻读?

        首先要理解当前读和快照读,当前读是指读最新的数据,快照读是指Read View 读 undolog的数据。隔离性RR级别 事务第一次读的时候会建立一个读视图Read View

假设有如下业务场景:

| 时间 | 事务1                                                        | 事务2                                       |
| ---- | ------------------------------------------------------------ | ------------------------------------------- |
|      | begin;                                                      |                                             |
| T1   | select * from user where age = 20;2个结果                    |                                             |
| T2   |                                                              | insert into user values(25,'25',20);commit; |
| T3   | select * from user where age =20;2个结果                     |                                             |
| T4   | update user set name='00' where age =20;此时看到影响的行数为3 |                                             |
| T5   | select * from user where age =20;三个结果                    |                                             |

执行流程如下:

1、T1时刻读取年龄为20 的数据,事务1拿到了2条记录

2、T2时刻另一个事务插入一条新的记录,年龄也是20 

3、T3时刻,事务1再次读取年龄为20的数据,发现还是2条记录,事务2插入的数据并没有影响到事务1的事务读取

4、T4时刻,事务1修改年龄为20的数据,发现结果变成了三条,修改了三条数据

5、T5时刻,事务1再次读取年龄为20的数据,发现结果有三条,第三条数据就是事务2插入的数据,此时就产生了幻读情况

如何解决幻读问题

加排他锁(写锁)或者叫X锁  for update


| 时间 | 事务1                                        | 事务2                                                |
| ---- | -------------------------------------------- | ---------------------------------------------------- |
|      | begin;                                       |                                                      |
| T1   | select * from user where age =20 for update; |                                                      |
| T2   |                                              | insert into user values(25,'25',20);此时会阻塞等待锁 |
| T3   | select * from user where age =20 for update; |                                                      |

此时,可以看到事务2被阻塞了,需要等待事务1提交事务之后才能完成,其实本质上来说采用的是间隙锁的机制解决幻读问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值