MySQL中的锁

首先说说锁是干啥的?
Java中的锁是用来控制多个线程对共享资源的访问的。
我理解的MySQL中的锁就是用来控制多个事务对数据的访问的。
根据粒度大小分为三种:全局锁、表锁、行锁
全局锁(非重点):锁定数据库中所有的表,常用于数据备份
看表锁行锁之前先看看共享锁(Share Lock)排他锁(Exclusive Lock)
不管是表级锁还是行级锁,都包含这两种锁

从共享锁和排他锁角度说锁

图片.png先放一张图。源自小林coding

共享锁(Share Lock)

“共享锁满足读读共享,读写互斥”
这句话在各种八股里看了无数遍,我的理解是:
一个事务给一个行记录或者一张表加了共享锁后,其他事务还可以读取数据,但是不能修改数据。

表级别共享锁

当我们通过命令给一个表添加共享锁后,其他事务对这张表还可以读取数据,不能修改数据。
表级别共享锁命令:

/表级别的共享锁,也就是读锁;
lock tables t_student read;

lock tables 表名 read

行级别共享锁

当一个事务给一个行记录加了共享锁,其他事务还可以读这个行记录,但是其他事务不能修改这个行记录了。
行级别共享锁命令:

//对读取的记录加共享锁(S型锁)
select ... lock in share mode;

排他锁(Exclusive Lock)(独占锁)

“排他锁满足写写互斥,读写互斥”
我的理解:
一个事务给一个行记录或者一张表加排他锁后,其他事务不能读取和修改其中数据。

表级别排他锁
//表级别的排他锁,也就是写锁;
lock tables t_stuent write;

一个事务给t_student表加排他锁,其他事务就不能读写其中的数据了。

行级别排他锁
//对读取的记录加排他锁
select ... for update;

一个事务给行记录加排他锁,其他事务就不能读写这个行记录了
此外,普通的delete语句和update语句都是行级锁的排他锁。

//对操作的记录加排他锁(X型锁)
update table .... where id = 1;

//对操作的记录加排他锁(X型锁)
delete from table where id = 1;

从表级锁和行级锁角度说锁

表级锁

共享锁、排他锁

上面演示过了。

//表级别的共享锁,也就是读锁;
lock tables t_student read;

//表级别的排他锁,也就是写锁;
lock tables t_stuent write;

值得注意的是,除了随着事务提交释放,表锁也可以通过命令释放

unlock tables
意向锁

简单理解:判断表里的行数据是否加了锁

行级锁

比较重要,行级锁有三种:记录锁(Record Lock)、间隙锁(Gap Lock)和临键锁(Next-Key Lock)
我认为这三种锁主要是SQL语句不同。

Record Lock

记录锁,顾名思义,锁住的是某条具体记录。所以SQL长这样

select * from student where id =6 for update

解释一下,这条SQL将学生表里id为6的记录锁定了,并且是排他锁。其他的事务不能读写id为6的这个学生了。
关键点应该是where这个条件,有条件才能查询到确定的某个行记录。等值查询。

Gap Lock

间隙锁,锁住的是两个记录之间,还没填数据的间隙,比如你给学生表添加了一条id为1的数据,又添加了一条id为6的数据,那么1到6之间,就是一个间隙。
SQL长这样

select * from student where id =3 for update;

或者

select * from t where id > 1 and id < 6 for update;

第一条SQL等值查询查到id为3,没命中任何一条Record,此时就会锁住1到6这个区间
第二题SQL范围查询查到id在1到6之间,没命中任何一条Record,所以锁住1到6这个区间

并且这两条SQL都是排他锁,其他事务不能读写这个区间

Next-Key Lock(MySQL默认行锁)

临键锁,是Record Lock+Gap Lock组成的锁。根据上面两种锁的特性,临键锁既锁记录也锁区间
具体锁住的记录是区间右边的记录,比如区间(1,8],用临键锁的话锁的记录是id=8,锁的区间是1~8。
场景:
图片.pngSQL长这样:

select * from t where id > 5 and id <= 7 for update;

当我们使用范围查询时,命中了部分Record,此时锁住的就是临键区间
注意:临键锁锁住的区间会包含最后一个Record右边的临键区间
所以这条SQL锁住的区间是
(1,6],(6,8]

间隙锁+临键锁解决可重复读隔离级别下的当前读的幻读问题

说这个问题前还是说说快照读和当前读
快照读就是普通Select语句,不加锁,通过MVCC来保证不发生幻读。
回顾一下,因为可重复读隔离级别下,事务A开启时只创建一次ReadView,后面都复用这个ReadView,所以即时有其他事务B过来添加了数据,事务A再次查询的时候用的还是最初的ReadView,不会发生幻读。
当前读是指,除了普通Select,其他都是当前读,比如update、insert、delete、还有

select... lock in share mode

select...for update

都是当前读!

假设一个幻读场景
事务A读取一张表中所有数据
事务B添加一条数据
事务B提交
事务A再次读取,此时会发现表中数据多了一条,这就是幻读

那么假如事务B添加的数据的id在一个被锁住的间隙,就不能被添加了,这就是间隙锁和临键锁解决可重复读隔离级别下的当前读幻读问题。

over。。不想写了,估计也有好多处错
脑内:“我参透了符文”和“我还是啥也不会”

说人话面试题

讲讲MySQL里的锁吧

MySQL中的锁,按照锁粒度划分为全局锁,表锁和行锁,全局锁一般用于数据备份。我来说说表锁和行锁,不论是表锁还是行锁,从功能角度来讲,都分为共享锁和排他锁,S锁和X锁,那么共享锁又叫读锁,它是读读不互斥读写互斥的,意思是说一个事务给一张表或者记录加上共享锁,其他事务还能读取数据,但是不能修改数据。排他锁又叫写锁,它是读写互斥写写互斥的,意思就是一个事务给一张表或者一个记录加上排他锁,其他事务既不能读取数据也不能修改数据。
那么表锁除了普通的共享锁排他锁还有一个意向锁,他是用来判断表中是否有行锁的。
再来说说InnoDB才有的行锁,行锁有三种,记录锁、间隙锁和临键锁。
记录锁锁的是记录,场景是等值查询,一条SQL命中了一个Record,就加了记录锁。
间隙锁,锁住的是一个间隙,当一个SQL进行等值查询或者范围查询时,等值查询没查到记录,范围查询也没查到记录,就会锁住一个区间。
临键锁,记录锁+间隙锁,即锁记录也锁间隙,当一个SQL范围查询时,命中了部分记录,就会锁住命中的记录和他旁边的间隙,主要在可重复读隔离级别下解决当前读的幻读问题。

很难想象写了这么多,只能回答一道题,悟了
还要记住一点,除了普通Select,他叫快照读,不加锁,用的MVCC。其他SQL都要加锁

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值