MySQL InnoDB中的锁-临键锁(next-key lock)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: MySQL InnoDB 锁 临键锁 next-key lock

锁列表

  • 共享与列排他锁
  • 意向锁
  • 记录锁
  • 间隙锁
  • Next-Key锁
  • 插入意向锁
  • AUTO-INC锁

这次我们只来讨论和实验意向锁。

Next-Key锁

概述

Next-Key锁称为临键锁。
临键锁可以理解为锁住的是索引本身以及索引之前的间隙,是一个左开右闭的区间。当 SQL 执行按照非唯一索引进行数据的检索时,会给匹配到行上加上临键锁。

锁定区间

1.png

实验

以下实验基于MySQL 8.0.x版本。
建表语句:

CREATE TABLE `sys_user` ( `id` int NOT NULL AUTO_INCREMENT,
`name` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '姓名', 
`name_pinyin` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '姓名拼音',
`id_card` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '身份证号',
`phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '手机号', 
PRIMARY KEY (`id`), 
UNIQUE KEY `uni_idx_id_card` (`id_card`) USING BTREE COMMENT '唯一索引-身份证号', 
KEY `idx_phone_name` (`phone`,`name`) USING BTREE COMMENT '普通索引-手机号' ) ENGINE=InnoDB AUTO_INCREMENT=3495 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户'

插入记录

insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (1, '小六', 'xiaoliu', 300000000, 13000008000, 10);

insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (2, '小六', 'xiaoliu', 300000001, 13000008000, 11);

insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (3, '小六', 'xiaoliu', 300000002, 13000008000, 13);

insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (4, '小六', 'xiaoliu', 300000003, 13000008000, 20);

记录键存在的间隙区间:

  1. (负无穷大,10]
  2. (10, 11]
  3. (11, 13]
  4. (13, 20]
  5. (20, 正无穷大]

临键锁区间

  1. (负无穷大,10]
  • 间隙锁范围内插入

事务A:

begin;
select * from sys_user where age=10 for update;

事务B:

begin;
insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (5, '小六', 'xiaoliu', 300000004, 13000008000, 9);

结果:
事务B被阻塞,无法被插入。

  • 间隙锁范围外插入

事务A:

begin;
select * from sys_user where age=10 for update;

事务B:

begin;
insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (5, '小六', 'xiaoliu', 300000004, 13000008000, 11);

结果:
事务B正常插入,无阻塞。

  1. (11, 13]~(13, 20)
  • 间隙锁范围内插入,被阻塞

事务A:

begin;
select * from sys_user where age=13 for update;

事务B:

begin;
insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (6, '小六', 'xiaoliu', 300000005, 13000008000, 12);

结果:
事务B无法正常插入,被阻塞。

  • 间隙锁范围外插入,无阻塞正常插入

事务A:

begin;
select * from sys_user where age=13 for update;

事务B:

begin;
insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (67, '小六', 'xiaoliu', 300000006, 13000008000, 10);

结果:
事务B正常插入。

  1. (20, 正无穷大]
  • 间隙锁范围内插入被阻塞

事务A:

begin;
select * from sys_user where age=20 for update;

事务B:

begin;
// 以下两条都会阻塞
insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (67, '小六', 'xiaoliu', 300000006, 13000008000, 13);
insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (67, '小六', 'xiaoliu', 300000006, 13000008000, 100000);

结果:
事务B被阻塞。

  • 间隙锁范围外正常插入

事务A:

begin;
select * from sys_user where age=20 for update;

事务B:

begin;
insert into sys_user (id, name, name_pinyin, id_card, phone, age)values (67, '小六', 'xiaoliu', 300000006, 13000008000, 12);

结果:
事务B正常插入。

注意

  1. 建议尽可能让所有的查询都使用主键或者唯一索引,这样可以避免临键锁,预防对记录大面积的锁。

参考

  1. https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#innodb-record-locks
  2. https://www.infoq.cn/article/zau0ewzsdtx9zofr6c8w
  3. https://zhuanlan.zhihu.com/p/48269420
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
SQL 关系型数据库 MySQL
MySQL 锁
MySQL里常见的几种锁
53 3
|
12天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
119 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
12天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的表空间
InnoDB是MySQL默认的存储引擎,主要由存储结构、内存结构和线程结构组成。其存储结构分为逻辑和物理两部分,逻辑存储结构包括表空间、段、区和页。表空间是InnoDB逻辑结构的最高层,所有数据都存放在其中。默认情况下,InnoDB有一个共享表空间ibdata1,用于存放撤销信息、系统事务信息等。启用参数`innodb_file_per_table`后,每张表的数据可以单独存放在一个表空间内,但撤销信息等仍存放在共享表空间中。
|
12天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的段、区和页
MySQL的InnoDB存储引擎逻辑存储结构与Oracle相似,包括表空间、段、区和页。表空间由段和页组成,段包括数据段、索引段等。区是1MB的连续空间,页是16KB的最小物理存储单位。InnoDB是面向行的存储引擎,每个页最多可存放7992行记录。
|
12天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL的InnoDB存储引擎
InnoDB是MySQL的默认存储引擎,广泛应用于互联网公司。它支持事务、行级锁、外键和高效处理大量数据。InnoDB的主要特性包括解决不可重复读和幻读问题、高并发度、B+树索引等。其存储结构分为逻辑和物理两部分,内存结构类似Oracle的SGA和PGA,线程结构包括主线程、I/O线程和其他辅助线程。
【赵渝强老师】MySQL的InnoDB存储引擎
|
1月前
|
存储 关系型数据库 MySQL
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
58 1
|
1月前
|
存储 关系型数据库 MySQL
MySQL锁,锁的到底是什么?
【10月更文挑战第16天】MySQL 锁锁定的是与数据和资源相关的对象,其目的是为了保证数据的一致性、避免冲突,并在并发环境下合理协调事务或操作的执行。理解锁的对象和意义对于优化数据库性能、处理并发问题至关重要。
55 0
|
1月前
|
关系型数据库 MySQL 数据库
mysql锁详解
通过理解并合理运用MySQL中的锁机制,开发者可以有效管理数据库并发访问,平衡性能与数据一致性需求。更多关于MySQL锁的深入探讨和最佳实践,请参考专业的数据库管理资源[[深入MySQL锁机制详解
36 0
|
5月前
|
存储 关系型数据库 MySQL
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
|
1月前
|
存储 缓存 关系型数据库
详细解析MySQL中的innodb和myisam
总之,InnoDB和MyISAM各有千秋,选择合适的存储引擎应基于对应用程序特性的深入理解,以及对性能、数据完整性和可扩展性的综合考量。随着技术发展,InnoDB因其全面的功能和日益优化的性能,逐渐成为更广泛场景下的首选。然而,在特定条件下,MyISAM依然保留其独特的价值。
123 0
下一篇
无影云桌面