MySql 三大知识点,索引、锁、事务,原理分析( 二 )


Next-Key Lock(Record Lock + Gap Lock,锁定一个范围,并且锁定记录本身,MySql 防止幻读,就是使用此锁实现)
4.默认的读操作,上锁吗?
默认是 MVCC 机制(“一致性非锁定读”)保证 RR 级别的隔离正确性,是不上锁的 。
可以选择手动上锁:select xxxx for update (排他锁);
select xxxx lock in share mode(共享锁),称之为“一致性锁定读” 。
使用锁之后,就能在 RR 级别下,避免幻读 。当然,默认的 MVCC 读,也能避免幻读 。
【MySql 三大知识点,索引、锁、事务,原理分析】既然 RR 能够防止幻读,那么,SERIALIZABLE 有啥用呢?
防止丢失更新 。例如下图:

MySql 三大知识点,索引、锁、事务,原理分析

文章插图
 
这个时候,我们必须使用 SERIALIZABLE 级别进行串行读取 。
最后,行锁的实现原理就是锁住聚集索引,如果你查询的时候,没有正确地击中索引,MySql 优化器将会抛弃行锁,使用表锁 。
3.事务事务是数据库永恒不变的话题,ACID:原子性,一致性,隔离性,持久性 。
四个特性,最重要的就是一致性 。而一致性由原子性,隔离性,持久性来保证 。
原子性由 Undo log 保证 。Undo Log 会保存每次变更之前的记录,从而在发生错误时进行回滚 。隔离性由 MVCC 和 Lock 保证 。这个后面说 。持久性由 Redo Log 保证 。每次真正修改数据之前,都会将记录写到 Redo Log 中,只有 Redo Log 写入成功,才会真正的写入到 B+ 树中,如果提交之前断电,就可以通过 Redo Log 恢复记录 。
然后再说隔离性 。
隔离级别:
1、未提交读(RU)
2、已提交读(RC)
3、可重复读(RR)
4、串行化(serializable)
每个级别都会解决不同的问题,通常是3 个问题:脏读,不可重复读,幻读 。一张经典的图:
 
MySql 三大知识点,索引、锁、事务,原理分析

文章插图
 
 
这里有个注意点,关于幻读,在数据库规范里,RR 级别会导致幻读,但是,由于 Mysql 的优化,MySql 的 RR 级别不会导致幻读:在使用默认的 select 时,MySql 使用 MVCC 机制保证不会幻读;
你也可以使用锁,在使用锁时,例如 for update(X 锁),lock in share mode(S 锁),MySql 会使用 Next-Key Lock 来保证不会发生幻读 。前者称为快照读,后者称为当前读 。
原理剖析:
1、RU 发生脏读的原因:RU 原理是对每个更新语句的行记录进行加锁,而不是对整个事务进行加锁,所以会发生脏读 。而 RC 和 RR 会对整个事务加锁 。
2、RC 不能重复读的原因:RC 每次执行 SQL 语句都会生成一个新的 Read View,每次读到的都是不同的 。而 RR 的事务从始至终都是使用同一个 Read View 。
3、RR 不会发生幻读的原因: 上面说过了 。
那 RR 和 Serializble 有什么区别呢?答:丢失更新 。本文关于锁的部分已经提到 。
MVCC 介绍:全称多版本并发控制 。
innoDB 每个聚集索引都有 4 个隐藏字段,分别是主键(RowID),最近更改的事务 ID(MVCC 核心),Undo Log 的指针(隔离核心),索引删除标记(当删除时,不会立即删除,而是打标记,然后异步删除);
本质上,MVCC 就是用 Undo Log 链表实现 。
MVCC 的实现方式:事务以排它锁的方式修改原始数据,把修改前的数据存放于 Undo Log,通过回滚指针与数据关联,如果修改成功,什么都不做,如果修改失败,则恢复 Undo Log 中的数据 。
多说一句,通常我们认为 MVCC 是类似乐观锁的方式,即使用版本号,而实际上,innoDB 不是这么实现的 。当然,这不影响我们使用 MySql 。




推荐阅读