一、表锁和行锁
锁是为了保证并发场景下数据读写的一致性。当一个事务对某一条数据上锁之后,其他事务就不能修改或者只能阻塞等待锁的释放。加锁之后,直到加锁的事务结束(提交或者回滚)才会释放锁。因此锁的粒度决定了数据读写的并发度,从而影响数据库的性能。通常数据库锁的粒度可以分为表锁和行锁。
表锁
当前操作会对整张表加锁,一旦这张表加了写锁,其他人就不能读写该表。MyISAM引擎中就只有表锁。 1. 优点
- 实现逻辑简单,开销小。
- 获取锁和释放锁的速度快。
- 由于表级锁一次会将整个表锁定,所以能很好的避免死锁问题。
2. 缺点 由于锁粒度最大,因此出现争用被锁定资源的概率也会最高,致使并发度十分低下。
LOCK TABLE 表名 READ/WRITE; --加读/写锁
UNLOCK TABLE; --解锁
意向锁 当事务A对某个表的某些数据加了锁,而事务B想给该表加表锁,要怎么办?如果需要遍历整张表来检查该表是否加锁,加锁效率就很低了,因此MySQL引入了意向锁。当需要给一张表上表锁的时候,只需要看这张表是否有对应的意向锁就可以了,无需遍历整张表。意向锁是MySQL自己维护的,用户无法手动加意向。
意向共享锁(Intention Shared Lock,IS锁): 当需要给一行数据加上S锁的时候,MySQL会先给这张表加上IS锁
意向排他锁(Intention Exclusive Lock,IX锁): 当需要给一行数据加上X锁的时候,MySQL会先给这张表加上
意向锁之间是不会产生冲突的,它只会阻塞表级读锁或表级写锁。另外,意向锁也不会和行锁冲突,行锁只会和行锁冲突。 可兼容的锁:S-S, S-IS, IS-IS,IS-IX
页级锁:
粒度介于行锁和表锁之间,并发度一般,会出现死锁。
行锁
只针对当前操作的行加锁,锁粒度较小,提高了并发度。 InnoDB行锁是通过给索引上的索引项加锁来实现的,这样加锁时只需要查询索引树,而不需要遍历整张表。只有通过索引条件检索数据,InnoDB才使用行级锁,否则当前操作会退化为表锁。
二、锁的类型
共享锁
共享锁(Shared Lock),又称为读锁(S锁)。当一条数据被加了S锁之后,其他事务也可以读取该数据,但不能进行修改(即其他事务可对该数据加S锁,但不能加X锁)。
select * from user where id=1 LOCK IN SHARE MODE; -- 加共享锁
排他锁
排他锁(Exclusive Lock),又称为写锁(X锁)。当一条数据被加了X锁之后,其他事务想来访问这条数据只能阻塞等待锁的释放,具有排他性。for update、DML(update/delete/insert)操作会加X锁。
排他锁又可以细分为以下几种锁: 1、记录锁(Record Lock): 锁住某一行记录 2、间隙锁(Gap Lock): 锁住某个范围的记录 3、临键锁(Next-key Lock): 上面两者加起来的效果 4、插入意向锁(LOCK_INSERT_INTENTION): 5、意向排它锁(IX):lock mode IX
如果MySQL行锁只是锁住一行记录,是不能防止幻读的。因此有了间隙锁锁住某个数据区间,来防止数据的插入,解决幻读问题。 注意了,这里仅针对RR隔离级别,对于RC隔离级除了外键约束和唯一性约束会加间隙锁,没有间隙锁,自然也就没有了临键锁,所以RC级别下加的行锁都是记录锁,没有命中记录则不加锁,所以RC级别是没有解决幻读问题的。
临键锁在以下两个条件时会降级成为间隙锁或者记录锁:
- 当查询未命中记录时,会降级为间隙锁。
- 当使用主键或者唯一索引命中了一条记录时,会降级为记录锁。
假设user表数据如下,ID为唯一主键
| 标题 | |
|---|---|
| ID | name | | 1 | Lily | | 5 | Tom | | 20 | Sandy |
记录锁: 1, 5 , 10 间隙锁划分如下: (-∞,1), (1,5), (10,+∞) 临键锁(左开右闭) (-∞,1], (1,5], (10,+∞)
临键锁中锁住的范围是最后一个命中记录的 key 和其下一个左开右闭的区间
检验X锁的锁定区间
drop table if exists `test`;
CREATE TABLE `test` (
`id` int NOT NULL PRIMARY KEY,
`a` int,
`b` int,
key `NAME_INDEX` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO test VALUE(1,1,1);
INSERT INTO test VALUE(5,5,5);
INSERT INTO test VALUE(10,10,10);
唯一索引等值查询:
- 当查询的记录是存在的,next-key lock 会退化成「记录锁」。
- 当查询的记录是不存在的,next-key lock 会退化成「间隙锁」。
非唯一索引等值查询:
- 当查询的记录存在时,除了会加 next-key lock 外,还额外加间隙锁,也就是会加两把锁。
- 当查询的记录不存在时,只会加 next-key lock,然后会退化为间隙锁,也就是只会加一把锁。
非唯一索引和主键索引的范围查询的加锁规则不同之处在于:
- 唯一索引在满足一些条件的时候,next-key lock 退化为间隙锁和记录锁。
- 非唯一索引范围查询,next-key lock 不会退化为间隙锁和记录锁。
三、死锁的条件 四、死锁案例 五、死锁的解决方案
参考文章:
作者:熬夜不加班
链接:juejin.cn/post/688561…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。