MySQL的锁、MVCC与事务的实现关系

因为我在B站上按照主题学的,所以没有很系统的学习,导致我对锁、MVCC与事务的隔离实现整体结构不是很清晰,查了一上午的资料终于可以做个总结啦。所以时间允许的话,最好还是要系统的踏实的啃透知识点!

先给个总结吧,我们都知道事务的四个特点ACID,基于redo log 、undo log以及MVCC和锁。

        其中undolog以链表的形式保存了每次修改的版本,这样在出错时就可以undolog中的记录执行相反操作就可以达到回滚的目的,从而实现原子性(A);

        redo log保证了持久性(D),我们都知道数据库是保存在磁盘上的,如果每次更改都直接写回正确的数据库位置(这是一种随机读取),效率十分低,而且如果系统突然崩溃或者断电,那么数据就直接丢失了,为了解决这个问题,可以将修改的数据直接顺序写入redo log的buffer(内存),然后对redo log进行持久化,等空闲时在对数据库进行更新,因为是顺序写入,是十分快速的,所以保证了持久性;

        先说下一致性吧,其实它要通过AID来保障的,所以也是最重要的;

        最后就是我总结的重点,隔离性,事务的四个特点其实就是可靠性和并发性两个方面,隔离性I就是为了更好的实现并发。众所周知,隔离级别分为四个,未提交读,已提交读,可重复读和串行读,可以分级的解决脏读,不可重复读以及幻读的问题。

开始总结之前,先介绍两个知识点:

        当前读:读的是最新的内容,update,insert,delete以及select... for update,select... lock in share mode都是当前读

        快照读:读的是历史版本,select...(至于是哪个历史版本,也就是说可见的是那种,请看我下面MVCC的可见性算法就明白啦)

开始本文的重点吧!

1、想先介绍下MVCC,因为它的知识比较少,而且很整齐。MVCC,多版本控制并发,是一个通过记录历史版本来实现读写分离的技术,从而提高并发性。为了实现MVCC,首先需要借助undolog中的历史记录,而且为了区分版本先后顺序,innodb为每个记录增加了3个字段,分别是DB_TRX_ID(事务序号),DB_ROW_ID(聚簇索引涉及的行号),DB_ROLL_PTR(回滚指针);那么在进行快照读时生成的readview,它会显示当前事务可见的记录,以及额外的几个信息用来约束哪些可见,trx_list(当前活跃的事务序号),up_limit_id(列表中事务ID最小值),low_limit_id(系统中尚未命名的下一个事务序号)。那么undolog中记录db_trx_id能否可见只要根据下面的判断即可:

                db_trx_id<up_limit_id:事务开始前就提交了,自然可以看到;

                db_trx_id>=low_limit_id,事务开始后才有的,自然不可见

                db_trx_id介于up和low直接的,只要判断db_trx_id是否在trx_list中即可,在就是不可见的,因为还没有提交。

2、接下来我们介绍锁;锁按照粒度分为表锁和行锁,且行锁仅针对真正用到了索引列才有效,否则会退化为表锁。

先总结下MyISAM中不会发生死锁的表锁,有共享锁和独占锁,写优先,所以MyISAM不适合高并发,且只适合只读的,否则频繁写时总是读阻塞;

接下来就是INNODB中常常涉及的几种锁:共享锁,排他锁,间隙锁,记录锁,next-key锁,悲观锁、乐观锁,行锁。他们之间的关系是什么呢:

首先行锁,间隙锁、记录锁、next-key锁都是概念性的,具体的实现是排他锁和共享锁;而悲观锁和乐观锁更不是具体的锁,他们指的是一种设计思想。

innodb会自动为update delete insert添加写锁,select不会加锁,但可以通过显示的方式(for update:写锁;lock in share mode:读锁)。

        共享锁:不堵塞,多个用户可以同时读一个资源,互不干扰。

        排他锁:一个写锁会阻塞其他的读锁和写锁,这样可以只允许一个用户进行写入,防止其他用户读取正在写入的资源

        表锁:系统开销最小,会锁定整张表,MyIsam 使用表锁。
        行锁:最大程度的支持并发处理,但是也带来了最大的锁开销,InnoDB 使用行锁。        
具体可见: https://blog.csdn.net/a303549861/article/details/100302267

另外,这里要澄清下常常提到的悲观锁和乐观锁,他们并不是真正的具体锁,而是一种抽象分类,包括很多具体的实现方式,与之并列的还有MVCC;

其实并发引起的冲突无非两种,读-写和写-写

具体可见:【MySQL笔记】正确的理解MySQL的乐观锁,悲观锁与MVCC_长路漫漫的歇脚处-CSDN博客

3、锁和MVCC合作完成隔离级别的实现:

(1)未提交读:写+锁,读不加锁;

(2)已提交读:写+锁,读利用MVCC的快照读,而且每次访问都会重新生成快照;

(3)可重复读:写+锁,读利用MVCC的快照读,而且只有在事务内第一次访问时才会生成快照;

(4)串行读:写+锁,读+锁

其中RC和RR的写时用的锁与隔离级别有关,可能是行锁,也可能是间隙锁;

在RC级别下,即使索引使用范围条件,仍然是行锁;

在RR级别下,索引使用=,为行锁,使用范围,为间隙锁;

在可重复读隔离级别下并不能避免幻读,如果要避免的话需要使用Next-Key Lock。但是有了Next-Key Lock以后,会导致并发插入的时候产生等待,所以这时候需要进行相关的优化。

        

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值