MySQL 锁

1.锁的种类

  • 按兼容性划分:共享锁(S Lock)、排他锁(X Lock)
  • 按锁粒度划分:表锁、行锁
  • 按锁模式划分:记录锁、间隙锁、临键锁、意向锁、插入意向锁
  • 按加锁机制划分:乐观锁、悲观锁
    在这里插入图片描述

2.按兼容性划分

(1)共享锁

共享锁(S Lock)也叫读锁(read lock)。共享指读读共享 。也就是说,无论是行级或是表级,如果对某数据上了共享锁 ,允许其他事务也加共享锁,共享锁和共享锁不互斥),但是不能写,也就是读写互斥

普通的select语句是什么锁都不上的,所谓的读读共享,读写互斥,写写互斥 ,都是对于锁资源来说的,如果没有锁资源竞争,就不存在什么互斥了。

select * from table1 lock in share mode; // 同时还是表锁
select * from table1 where id = 1 lock in share mode; // id为索引,同时还是行锁

(2)排他锁

除了select … for update,InnoDB引擎对修改 、插入、删除(update、insert。delete)都是给相关数据加排他锁。

select * from table1 for update; // 同时还是表锁
select * from table1 where id = 1 for update; // id为索引,同时还是行锁

3. 按锁粒度划分

(1)表锁

并发度低,不会出现死锁。开销小,加锁快。

select * from table1 lock in share mode; 
select * from table1 for update;

(2)行锁

并发度高,会出现死锁。开销大,加锁慢。

select * from table1 where id = 1 lock in share mode;
select * from table1 where id = 1 for update;

(3)注意

在InnoDB 下, 不是想用行锁就用行锁的,行锁的触发条件:
在这里插入图片描述

4.按锁模式划分

(1)(2)(3)为行锁的三种实现算法。间隙锁 和 临键锁 是用来解决幻读问题的,在已提交读 隔离级别下会失效。
(4)也是行存在的锁。
(5)是表级锁。

(1)记录锁

直接锁定某行数据。

select * from table1 where id = 1 lock in share mode;
select * from table1 where id = 1 for update;

在这里插入图片描述

(2)间隙锁

间隙指的是两个记录之间逻辑上尚未填入数据的部分,是一个左开右开空间。

间隙锁就是锁定某些间隙区间的。当我们使用等值查询或者范围查询,并没有命中任何一个记录时,就会将对应的间隙区间锁定。

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

在这里插入图片描述

(3)临键锁

临键指的是间隙加上它右边的记录组成的区间。

临键锁 是 记录锁 和 间隙锁 的组合,即除了锁住记录本身,还要再锁住索引之间的间隙。
在这里插入图片描述

(4)插入意向锁

插入意向锁是一种间隙锁形式的意向锁,在真正执行 INSERT 操作之前设置。

当执行插入操作时,总会检查当前插入操作的下一条记录(已存在的主索引节点)上是否存在锁对象,判断是否锁住了 gap,如果锁住了,则判定和插入意向锁冲突,当前插入操作就需要等待,也就是配合上面的间隙锁或者临键锁一起防止了幻读操作。

因为插入意向锁是一种意向锁,意向锁只是表示一种意向,所以插入意向锁之间不会互相冲突,多个插入操作同时插入同一个 gap 时,无需互相等待,比如当前索引上有记录 4 和 8,两个并发 session 同时插入记录 6,7。他们会分别为(4,8)加上 GAP 锁,但相互之间并不冲突

INSERT 语句在执行插入之前,会先在 gap 中加入插入意向锁,如果是唯一索引,还会进行 Duplicate Key 判断,如果存在相同 Key 且该 Key 被加了互斥锁,则还会加共享锁,然后等待(因为这个相同的 Key 之后有可能会回滚删除,这里非常容易死锁)。等到成功插入后,会在这条记录上加排他记录锁
在这里插入图片描述

(5)意向锁

意向锁的出现是为了支持InnoDB的多粒度锁,它解决的是表锁和行锁共存的问题。

当我们需要给一个表加表锁的时候,我们需要根据去判断表中有没有数据行被锁定,以确定是否能加成功。

假如没有意向锁,那么我们就得遍历表中所有数据行来判断有没有行锁;

有了意向锁这个表级锁之后,则我们直接判断一次就知道表中是否有数据行被锁定了。

有了意向锁之后,要执行的事务A在申请行锁(写锁)之前,数据库会自动先给事务A申请表的意向排他锁。当事务B去申请表的互斥锁时就会失败,因为表上有意向排他锁之后事务B申请表的互斥锁时会被阻塞。
在这里插入图片描述

5.按加锁机制划分

(1)悲观锁

悲观锁认为被它保护的数据是极其不安全的,每时每刻都有可能被改动,一个事务拿到悲观锁后,其他任何事务都不能对该数据进行修改,只能等待锁被释放才可以执行。

数据库中的行锁,表锁,读锁,写锁均为悲观锁。

(2)乐观锁

https://blog.csdn.net/a20100997/article/details/123031755

乐观锁认为数据的变动不会太频繁。

乐观锁通常是通过在表中增加一个版本(version)或时间戳(timestamp)来实现,其中,版本最为常用。

事务在从数据库中取数据时,会将该数据的版本也取出来(v1),当事务对数据变动完毕想要将其更新到表中时,会将之前取出的版本v1与数据中最新的版本v2相对比,如果v1=v2,那么说明在数据变动期间,没有其他事务对数据进行修改,此时,就允许事务对表中的数据进行修改,并且修改时version会加1,以此来表明数据已被变动。

如果,v1不等于v2,那么说明数据变动期间,数据被其他事务改动了,此时不允许数据更新到表中,一般的处理办法是通知用户让其重新操作。不同于悲观锁,乐观锁通常是由开发者实现的。

6.死锁的解决

(1)查看死锁

1、查看正在进行中的事务
SELECT * FROM information_schema.INNODB_TRX

2、查看正在锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

3、查看等待锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

4、查询是否锁表
SHOW OPEN TABLES where In_use > 0;

5、查看最近死锁的日志
show engine innodb status

(2)解除死锁

查看当前正在进行中的进程
show processlist;
SELECT * FROM information_schema.INNODB_TRX;
杀掉进程对应的进程id
kill idl
验证
SHOW OPEN TABLES where In_use > 0;
  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值