前段时间看一些面经,感觉自己MySQL锁这一块知识很零碎,决定系统地记录一下。
阅读之前默认读者已了解前置知识,也就是事务隔离级别之类的。
锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算机资源(如CPU、RAM、I/O等)的争用外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。
说明:只有「明确」指定主键,才会执行锁,否则将会执行表锁
示例
假设有个表 products ,字段id、name、type,id是主键。
无锁
# 明确指定主键,但不存在该主键的值(没有数据,当然不会有锁)
SELECT * FROM products WHERE id=-1 FOR UPDATE;
行锁
# 明确指定主键
SELECT * FROM products WHERE id=3 FOR UPDATE;
SELECT * FROM products WHERE id=3 AND type=1 FOR UPDATE;
表锁
# 主键不明确
SELECT * FROM products WHERE name=‘Mouse‘ FOR UPDATE;
SELECT * FROM products WHERE id<>‘3‘ FOR UPDATE;
SELECT * FROM products WHERE id LIKE ‘3‘ FOR UPDATE;
注意
Record Lock(普通行锁)
Gap Lock(间隙锁)
比如一张表没有id为10~20 的字段,我锁了130之间的所有值,那么插入值如果在1020之间的话,也会被阻塞,在某些情况下会极大地浪费性能。
Next-Key Lock(行 & 间隙)
对于存在于不存在的数据同时加锁,则称为" Next-Key Lock ";
Next-Key Lock包含Record Lock和Gap Lock;
# 假如user表中只有101条记录,empid的值是1,2,...,100,101
# 范围条件的检索,会对值为101的记录加锁,也会对大于101(不存在)加锁
# 由于两个锁同时存在,则此处为 Next-Key Lock
select * from user where user_id > 100 for update;
意向锁
自增锁
事务插入自增类型的列时获取自增锁
如果一个事务正在往表中插入自增记录,所有其他事务的插入必须等待
共享锁 & 排它锁
行锁和表锁是锁粒度的概念,共享锁和排它锁是他们的具体实现
共享锁(S):读锁
排它锁(X):写锁
注意
乐观锁 & 悲观锁
不管是什么锁都需要增加,需加失败重试
通过版本号来进行更新的操作属于乐观锁
update tab set name = ‘xxx‘ where id = 1 and version = xxx
共享锁 & 排它锁都是悲观锁的具象实现
原文:https://www.cnblogs.com/feiwuqianqi/p/13344476.html