mysql中InnoDB事务隔离的记录锁、间隙锁和临键锁
作者:Hello-Brand
InnoDB默认的事务隔离级别为可重复读(Repeated Read, RR),我们当下的所有介绍都是基于这个隔离级别为前提的。
- 记录锁(Record Locks):锁定单一行记录,InnoDB 使用记录锁来实现行级锁,这样允许多个事务并发访问不同的行。
- 间隙锁(Gap Locks):InnoDB 的特性,用于锁定一个范围,但不包括实际的记录。这主要用于防止幻读(Phantom Reads)。
- 临键锁(Next-Key Locks):InnoDB 存储引擎的一种锁定机制,在执行查询语句时,根据查询条件所锁定的一个范围。这个范围中包含有间隙锁和记录锁。它的设计目的是为了解决幻读(Phantom Reads)。
记录锁(Record Locks)
记录锁,它封锁索引记录,例如:
select * from table where id=5 for update;
它会在id=1的索引记录上加锁,以阻止其他事务插入,更新,删除id=1的这一行。
需要说明的是:
select * from table where id=5;
则是快照读(SnapShot Read),它并不加锁,快照读可以参考作者这篇文章:数据库系列:RR和RC下,快照读的区别
间隙锁(Gap Locks)
间隙锁,它封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。
延续上面的那个例子继续演示:
# 表结构 table (Id PK, Name , Company); # 表中包含四条记录 5, Gates, Microsoft 7, Bezos, Amazon 11, Jobs, Apple 14, Elison, Oracle
执行SQL语句如下:
select * from table where id between 7 and 13 for update;
这样的话,会封锁数据的区间,以防止其他事务插入id=8的记录。
假设没有间隙锁,则可能够插入成功,而之前的select事务,会发现检索的结果集莫名多了一条记录,即幻影数据。
所以间隙锁主要目的用于防止幻读(Phantom Reads),避免其他事务在间隔中插入数据,导致 『不可重复读』。
如果把事务的隔离级别降级为读提交(Read Committed, RC),对,就是互联网最常用的隔离级别,间隙锁则会自动失效。
临键锁(Next-Key Locks)
临键锁(Next-Key Locks)是数据库管理系统InnoDB中的一种重要锁定机制。这种锁是查询时根据查询条件锁定的一个范围,这个范围包括间隙锁和记录锁,左开右闭,即不锁住左边界,但会锁住右边界。临键锁的主要设计目的是为了解决所谓的“幻读”问题。
# 左开右闭 示例 (-infinity, 1] (1, 7] (7, 9] (9, +infinity]
依然沿用上面的例子,InnoDB引擎,RR隔离级别:
-- 创建一个示例表 CREATE TABLE users ( Id INT PRIMARY KEY, Name VARCHAR(255) NOT NULL, Company VARCHAR(255) NOT NULL, ); -- 插入一些示例数据 INSERT INTO users (id, name, company) VALUES (1, 'Alice', 'ali'); INSERT INTO users (id, name, company) VALUES (2, 'Brand', 'tencent'); INSERT INTO users (id, name, company) VALUES (3, 'Charlie', 'baidu'); -- 开始一个事务,并使用临键锁查询数据 START TRANSACTION; SELECT * FROM users WHERE id > 1 FOR UPDATE; -- 在另一个事务中尝试插入新数据,将会被阻塞直到第一个事务释放锁 START TRANSACTION; INSERT INTO users (id, name, age) VALUES (4, 'David', 30); COMMIT; -- 第一个事务提交后,第二个事务可以继续执行插入操作 COMMIT;
临键锁的主要目的,也是为了避免幻读(Phantom Read),在事务隔离级别为可重复读的情况下,InnoDB存储引擎默认使用临键锁。这种锁提供了一种有效的机制来保证在并发环境中数据的完整性和一致性。
如果把事务的隔离级别降级为RC,临键锁则也会失效。
总结
- InnoDB的索引与行记录存储在一起,MyISAM则是通过索引的地址查找到对应的数据记录,效率低一些
- InnoDB的聚集索引存储行记录,普通索引存储PK,所以普通索引要查询两次
- 记录锁锁定索引关联的具体记录
- 间隙锁锁定间隔,防止间隔中被其他事务插入
- 临键锁锁定索引记录+间隔,防止幻读
- select...for update加锁的几种情况:
- 主键字段:加行锁。
- 唯一索引字段:加行锁。
- 普通索引字段:加行锁。
- 主键范围:加多个行锁。
- 普通字段:加表锁。
- 查询空数据:不加锁。
- 行锁与表锁的区别
- 如果事务1加了行锁,一直未释放锁,事务2操作相同记录,会一直等待直至超时。
- 如果事务1加了表锁,一直未释放锁,事务2无论操作哪一行记录,都会一直等待直到超时
到此这篇关于mysql中InnoDB事务隔离的记录锁、间隙锁和临键锁的文章就介绍到这了,更多相关InnoDB的记录锁、间隙锁和临键锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!