从零蛋开始学mysql小册_MySQL 锁

本系列学习笔记旨在作者准备数据库方面面试用,有点临阵磨枪的感觉,我学习MySQL是参考的掘金小册的《MySQL 是怎样运行的:从根儿上理解 MySQL》和《MySQL 是怎样使用的:从零蛋开始学习 MySQL》,学习笔记里将核心概念和高频考点总结一下,图都是从小册里摘取的,如果涉及侵权可随时撤销,如果大家是零基础学习MySQL,强烈推荐上面的两本小册。

这一部分先针对面试题总结,后续视情况再完善。

1、MySQL解决并发问题的两种策略

事务那一篇文章介绍了数据库并发场景会出现的一系列问题,即脏写、脏读、不可重复读和幻读,以及不同事物隔离级别对应的并发问题,那怎么解决这些并发场景的问题呢?有以下两种方案:

(1)读操作采用MVCC(多版本并发控制),写操作采用加锁的方式

MVCC机制在查询之前生成一个ReadView,查询语句只能读取到生成ReadView之间已经提交的事务所做的修改,在生成ReadView之前未提交的事务或者生成ReadView之后才提交的事务所做的更改是读取不到的。MVCC机制可以不通过加锁的机制实现读-写不冲突,性能上肯定优于加锁,因此在场景运行的前提下优先使用MVCC机制。

(2)读、写操作均采用加锁的方式

MVCC机制是可以允许读取记录的旧版本的,但某些场景,比如银行转账时必须读取当前账户的最新记录,因此对读操作也加锁,保证每次读取的都是记录的最新版本。

2、基于锁粒度对MySQL中的锁的分类

不同数据库对锁粒度的支持情况是不一样的,MySQL支持三种粒度的锁,分别是表锁、行锁和页锁,默认是行锁。

(1)表锁

表锁是MySQL中粒度最大的锁,表示对当前操作的整张表加锁,他实现简单,资源消耗较少,表锁分为表共享锁和表排他锁。

表锁的特点:开销小,加锁快,不会出现死锁,锁粒度大,发生锁冲突的概率最高,并发度最低。

(2)行锁

行锁是MySQL中粒度最小的锁,表示只针对当前操作的行进行加锁。行锁能减小数据库操作的并发冲突,加锁粒度最小,但加锁开销也是最大的,行锁分为共享锁和排他锁。

行锁的特点:开销大,加锁慢,会出现死锁,锁粒度最小,发送锁冲突的概率最小,并发度最高。

(3)页锁

页锁是MySQL中介于表锁和行锁中间粒度的一种锁,相当于两种锁的折中方案。

页锁的特点:开销和加锁时间界于表锁和行锁之间;会出现死锁,锁定粒度界于表锁和行锁之间,并发度一般。

3、基于锁的类别对MySQL中锁的分类

基于锁的类别,MySQL中锁分为两类:共享锁和独占锁。

(1)共享锁(Shared Locks)

简称S锁,又叫读锁。事务要读取一条记录时,首先需要获取该记录的共享锁,共享锁可以同时被多个事务获取。

(2)独占锁(Exclusive Locks)

简称X锁,又叫排他锁和写锁。事务要修改一条记录时需要先获取该记录的排他锁,同一时刻仅能有一个事务获取某记录的排他锁。

注意:S锁和S锁是互相兼容的,S锁和X锁是不兼容的,X锁和X锁也是不兼容的。兼容的意思是一个事务获得了锁后,同一时刻另一个事务也可以获得锁;不兼容的意思是同一时刻事务A获取了锁,其他事务都不能获取该锁,只能等待事务A结束后释放了锁才能获取。

行锁可以分为行共享锁和行独占锁,表锁也可以分为表共享锁和表独占锁,对于表锁,MySQL中还有意向锁的概念,分为意向共享锁和意向独占锁,如下:意向共享锁,英⽂名:Intention Shared Lock,简称IS锁。当事务准备在某条记录上加S锁时,需要先在表级别加⼀个IS锁;

意向独占锁,英⽂名:Intention Exclusive Lock,简称IX锁。当事务准备在某条记录上加X锁时,需要先在表级别加⼀个IX锁。

IS、IX锁是表级锁,它们的提出仅仅为了在之后加表级别的S锁和X锁时可以快速判断表中的记录是否被上锁,以避免⽤遍历的⽅式来查看表中有没有上锁的记录,也就是说其实IS锁和IX锁是兼容的,IX锁和IX锁是兼容的。

兼容性图在这里补充!

4、MySQL中行锁的实现

InnoDB是基于索引来完成行锁,InnoDB存储引擎的锁的算法有三种:·Record lock:单个行记录上的锁;

·Gap lock:间隙锁,锁定一个范围,不包括记录本身;

Next-key lock:record+gap 锁定一个范围,包含记录本身。

这一部分后续可能会补充。

5、死锁

什么是死锁?死锁是值两个或者两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用它们将一直阻塞在这里无法推进下去,此时称系统处于死锁状态,对应的进程称为死锁进程。表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB。

死锁产生的原因在于两个Session加锁的顺序不一样,导致造成锁的调用链出现死循环,因此解决死锁问题的一个策略是让不同的Session的加锁顺序保持一致。

常见的解决死锁的方法:如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。

设置锁超时时间,超过一定时间后,Session会释放掉持有的锁;

对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率。

6、乐观锁

在Java并发专栏里有对Java乐观锁和悲观锁的解释,这里迁移一下对数据库的乐观锁和悲观锁的解释如下:悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现方式:使用数据库中的锁机制;

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。实现方式:乐观锁一般会使用版本号机制或CAS算法实现。

乐观锁和悲观锁的使用场景:从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量;

但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行自旋,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。

7、常见面试题

参考链接2和链接3。

参考掘金小册​juejin.imEnjoyMoving:MySQL锁总结​zhuanlan.zhihu.com65ae14db351ce75fe1758c13c527df71.pngnewer大侠:MySQL面试题-锁​zhuanlan.zhihu.com593c065a5c08af897e23bb0c244e19a1.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值