分类
行锁&表锁
只有明确指定主键,才会执行行锁,否则执行表锁
-
无锁
select * from user where id = -1 for update; #主键不存在
-
行锁
select * from user where id = 1 for update; select * from user where id = 1 and name = ‘kk‘ for update; #只要where后的字段建了索引,就会用行锁
-
表锁
#主键不明确 select * from user where name = ‘kk‘ for update; select * from use where id <>3 for update;
锁算法(机制)
行锁算法
-
Record Lock(普通行锁)
#主键值在条件范围内,单个行记录上的锁 #记录存在
-
Gap Lock(间隙锁)
#主键值不存在条件范围内,叫做间隙GAP,引擎就会对这个间隙加锁。 #间隙锁,锁定一个范围,但不包括记录本身。GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况
-
Next-key Lock(行& 间隙锁)
#主键值一部分在条件范围内。 #比如user表id字段自增共50条数据。 select * from user where id >49; 1+2,锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。
表锁算法
-
意向锁(升级机制)
#当一个事务,带着表锁去访问被加了行锁的资源,此时,这个行锁就会升级为意向锁,将表锁住。 #Session A select * from user where id = 1 for update ; #Session B select * from user where name like ‘kkk%‘ for update; 那么Session A 就会升级成意向锁
-
自增锁
#事务插入自增类型的列时,获取自增锁。 #如果一个事务正在往表中插入自增记录,其他事务都必须等待。
实现
共享锁 & 排他锁
行锁和表锁是粒度的概念,共享锁和排他锁是他们的具体实现。
共享锁(S)
允许一个事务去读一行,阻止其他事务去获取该行的排他锁。
select lock in share mode #MySQL 8以下版本
select for share #MySQL 8以上版本,支持nowait、skip locked,配合自旋锁可以实现等待队列。
排他锁(X):写锁
允许持有排它锁事务读写数据,阻止其他事务获取该资源的共享锁和排它锁。
select for update\insert\delete\update
多并发版本控制MVCC
加锁是当前读,保证读取的是最新的数据;在隔离级别为REPEATABLE时,不加锁的select操作是快照读,有可能读到的不是最新的版本。ps:在串行级别下,快照读会退化成当前读。
乐观锁 & 悲观锁
-
乐观锁
一般通过版本号进行更新检查
-
悲观锁
利用数据库本身提供的锁去实现