Mysql系列-锁

2021-10-28  本文已影响0人  程序员fly

前言

面试过程中,对于锁知识点的考察,也是经常出现在面试过程中,常见面试题大概有这么几个,小伙伴们试下是否能否回答出来吧

Mysql设计锁这个玩意目的是处理多线程对共享资源的访问,在Mysq体系中我们知道处理并发访问共享资源的方法一般是加锁事务,也是InnoDB和MySiam最重要的不同点,今天我们一起研究下锁相关的知识。

锁分类

全局锁

概念

全局锁就是对整个数据库实例加锁,让整个数据库只读。一但加上全局锁之后,之后其他线程的一下语句就会被阻塞:数据更新语句(数据正删改),数据定义语句(建表,修好表的结果),更新事务的提交语句都会阻塞在那等着吧,等我完事你们再来。

全局锁的使用场景主要用来做全库的逻辑备份,如果不加全局锁,就会造成备份数据的一致性出现问题。因为备份系统得到的数据库不是在一个逻辑时间点上,视图逻辑不一致,小伙伴请看下面这个例子

如何加全局锁
  1. set global readonly=true ,数据库处于只读状态,更新数据你就进不来
  2. Mysql官方自带的逻辑备份数据mysqldump,使用参数-single -transaction时候,会在开始时候启动一个事务,拿到一致性视图(事务下一篇我们就开始了,小伙伴这里只需有个概念,一致性视图就是事务在我之前的认,在我之后的我就不认,你在我之后更新删除没啥用,我不认你)。数据库在备份的时候,推荐这个
  3. FTWRL(Flush table with read lock) Mysql提供的一个命令,功能就是让整个数据库处于只读状态,小伙伴肯定问了,这不是和set global readonly=true 一个意思,enen,还是有点不一样,不一样点主要有以下几点
    1. 客户端发生异常的话,FTWRL会自动释放全局锁
    2. set global readonly=true数据库读写分离的时候,主库写从库读,我们在一些逻辑操作的时候可能会用这个判断是不是从库

表级锁

概念

Mysql表级别的锁会将整个表锁住,锁粒度比较大,表级别锁主要分为两种,一种是表锁,一种是元数据锁(meta data lock,MDL)

表锁

加锁和解锁是这样干的

lock tables tb1 read/write;
// do something
unlock tables;//lock tables unlock tables会主动当前会话中的所有表锁

这个有个注意的点需要说下,lock tables除了会现在别的线程读写之外,也会限制本线程的一些操作,啥意思?上个例子

MDL
查询表级锁争用
这里有两个参数可以查看到表级锁的竞争情况,我们执行下面这个命令,会出现这两个参数
show STATUS like '%table%'

行级锁

Mysql行级锁是由各个引擎实现的,并不是所以的引擎都支持行级锁,比如MyISAM引擎不支持行级锁,我们处理并发的时候只能使用表级锁,这是MySIAM被InnoDB取代的原因之一。InnoDB支持行锁,关于InnoDB行锁需要记住以下几点
  1. InnoDB的行锁是针对索引加的锁,不是针对记录加的锁,如果索引失效情况话,行锁会升级为表锁
  2. InnoDB事务中,行锁是需要的时候才加上,加上之后不是立马释放,需要等到事务执行结束之后才会释放,也就是我们常说的两阶段锁协议

我们创建一个表,表中id不设置索引,我们通过两个窗口查询数据,我们会发现,行级锁会变成表锁

CREATE TABLE `user`  (
  `id` int(11) NOT NULL  COMMENT 'id值',
  `age` int(11) NULL DEFAULT NULL COMMENT '年龄'
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
insert INTO USER(id,age) value(1,1);
insert INTO USER(id,age) value(2,2);
insert INTO USER(id,age) value(3,3);

session A 查询id=1这一列,因为没有索引,所以行级锁变成表级锁,锁住整个表

session A

Session B查询id=2的时候,因为session A持有标记锁,session B只能等待,看那个红框,一直转圈圈

sessionB

接下来一起分析一下Mysql行级锁中的共享锁和排他锁

共享锁/排他锁
间隙锁

当我们程序范围查询的请求共享和排他锁的时候,InnoDB会给符合条件的已有记录的索引项添加锁,对于键值对在范围内但是不存在的记录,InnoDB会给这个间隙添加锁,也就是我们常说的间隙锁。(PS间隙锁解决Mysql幻读问题)

锁的两种机制

锁有两种机制,乐观锁和悲观锁,是两种常见的资源并发锁设计思路,有这两个玩意的主要为了解决数据丢失问题和脏读问题

乐观锁

每次别人提交访问数据的时候,认为这次访问改变数据的概率很低,不加锁,只要数据提交的时候,数据库冲突的话才会将数据锁住。这样可以避免等待长事务数据库加锁开销,提高系统的并发性,乐观锁不能解决脏读问题。

实现方式
  1. 基于版本号实现,当进行数据读操作的时候,将提交数据的版本信息和数据库对应记录的当前版本信息进行对比,若是提交的数据版本大于数据库的版本,进行更新,小于的话就认为是过期数据,数据不进行更改。
  2. 基于时间戳实现,数据库增加时间戳字段,进去数据更新的时候,比较是不是和自己开始的时候查的时间戳是否一致,如果一致代表没有其他数据进行操作,可以进行这次操作

悲观锁

悲观锁任务对数据库的每一次操作都会数据进行改变,所以在一开始就会将数据锁住,悲观锁往往依靠于数据库提供的锁机制,比如行锁,表锁来保证数据的排他性。

Q:这里问小伙伴一个问题,悲观锁加锁方式,你说说乐观锁会加锁嘛

A:乐观锁本身是不加锁的,只是更新的时候通过版本号什么的去比较数据有没有被其他线程改变。在实际开发过程中,可能在提交之间使用select for update语句做一下检查,然后再用Update提交

闲谈

感觉有帮助的同学还请关注点赞,这将对我是很大的鼓励~,公众号有自己开始总结的一系列文章,需要的小伙伴还请关注下个人公众号程序员fly,希望能一起成长。

巨人肩膀

https://www.cnblogs.com/boblogsbo/p/5602122.html

https://www.cnblogs.com/jian0110/p/12721924.html

https://time.geekbang.org/column/intro/100020801

https://blog.51cto.com/qinbin/1968612

https://blog.csdn.net/sdyy321/article/details/6183412/

上一篇下一篇

猜你喜欢

热点阅读