mysql的锁
共 2622字,需浏览 6分钟
·
2022-03-16 13:44
作者:小强Zzz
来源:SegmentFault 思否社区
前言
mysql按锁的范围分三种
表级锁:开销小,加锁快;不会出现死锁,锁定粒度大,发生锁冲突概率最高,并发度最低。
行级锁:开销大,加锁慢,会出现死锁,锁定粒度小,发生锁冲突的概率最低,并发度最高。
页面锁:开销和加锁时间界于表锁和行锁之间,会出现死锁,锁定粒度界于表锁和行锁之间,并发度一般。
InnoDB的加锁模式
共享锁(S):允许一个事务读一行,阻止其他事务获得相同数据的排他锁,也叫读锁。
排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享锁与排他锁,也叫写锁。
同时mysql还支持与行共享锁和行排他锁类似的表共享锁和表排他锁因为锁的粒度不同,表锁的范围覆盖了行锁的范围,所以表锁和行锁会产生冲突,例如事务A对表中某一行数据加了行锁,然后事务B想加表锁,正常来说是应该要冲突的。要判断是否冲突就得遍历每一行数据了,这样的效率不高,因此我们就有了意向表锁。
意向锁的主要目的是为了使得 行锁 和 表锁 共存,事务在申请行锁前,必须先申请表的意向锁,成功后再申请行锁。
意向锁分为意向共享锁和意向排他锁。
意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁之前必须先去的该表的意向共享锁
意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的意向排他锁。
如果一个事务请求的锁模式与当前的锁模式兼容,InnoDB就将请求的锁授予该事务,反之,如果两者不兼容,该事务就要等待锁释放。
意向锁是表级锁,但是却表示事务正在读或写某一行记录,而不是整个表,所以意向锁之间不会产生冲突,真正的冲突在加行锁时检查。
加锁方法
显式上锁
select * from tableName lock in share mode;//读锁
select * from tableName for update;//写锁
解锁
提交事务(commit)
回滚事务(rollback)
kill阻塞进程
上读锁实例
因为InnoDB有MVCC机制(多版本并发控制),可以使用快照读,而不会被阻塞。
InnoDB行锁实现方式
行锁(Record Lock)
间隙锁(Gap Lock)
优点:解决了事务并发的幻读问题
不足:因为query执行过程中通过范围查找的话,他会锁定争个范围内所有的索引键值,即使这个键值并不存在。
间隙锁有一个致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成锁定的时候无法插入锁定键值范围内任何数据。在某些场景下这可能会对性能造成很大的危害。
Next-key Lock 锁
在Repeatable Read隔离级别下,Next-key Lock 是默认的行记录锁定算法。
假如teacher表中只有101条记录,其id值分别是1-101,SQL语句如下
Select * from teacher where id 〉 100 for update;
乐观锁与悲观锁
乐观锁(Optimistic Lock):假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。乐观锁不能解决脏读的问题。
悲观锁,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会被阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,都是在做操作之前先上锁。
总结
锁和多版本数据(MVCC)是 InnoDB 实现一致性读和四种隔离隔离级别的手段。
因此,在不同的隔离级别下,InnoDB 处理 SQL 时需要的锁是不同的。