InnoDB锁介绍

本文主要介绍MySQL InnoDB引擎中的各种锁策略和锁类别,并针对记录锁做演示以便于理解。

以下内容适用于MySQL 8.0版本。

读写锁

处理并发读/写访问的系统通常实现一个由两种锁类型组成的锁系统。这两种锁通常被称为共享锁(shared lock)和排他锁(exclusive lock),也叫读锁(read lock)和写锁(write lock)。

读锁

资源上的读锁是共享的,或者说是相互不阻塞的。多个客户端可以同时读取同一个资源而互不干扰。

写锁

写锁则是排他的,也就是说,一个写锁既会阻塞读锁也会阻塞其他的写锁,这是出于安全策略的考虑,只有这样才能确保在特定的时间点只有一个客户端能执行写入,并防止其他客户端读取正在写入的资源。

锁粒度

一种提高共享资源并发性的方式就是让锁定对象更有选择性。尽量只锁定包含需要修改的部分数据,而不是所有的资源。但是锁的范围越小,管理锁的逻辑就会越复杂,开销也越大。因此锁定策略是锁开销和数据安全性之间的平衡,这种平衡会影响性能。MySQL提供了两种粒度的锁。

表锁

InnoDB的表级别锁包含五种锁模式:LOCK_IS、LOCK_IX、LOCK_X、LOCK_S以及LOCK_AUTO_INC锁。

LOCK_IS/LOCK_IX

也就是所谓的意向锁,这实际上可以理解为一种“暗示”未来需要什么样行级锁,IS表示未来可能需要在这个表的某些记录上加共享锁,IX表示未来可能需要在这个表的某些记录上加排他锁。意向锁是表级别的,IS和IX锁之间相互并不冲突,但与表级S/X锁冲突。

在对记录加S锁或者X锁时,必须保证其在相同的表上有对应的意向锁或者锁强度更高的表级锁。

LOCK_X

当加了LOCK_X表级锁时,所有其他的表级锁请求都需要等待。X锁的几个情况:

  • DDL操作的最后一个阶段(ha_innobase::commit_inlace_alter_table)对表上加LOCK_X锁,以确保没有别的事务持有表级锁。通常情况下Server层MDL锁已经能保证这一点了,在DDL的commit 阶段是加了排他的MDL锁的。但诸如外键检查或者刚从崩溃恢复的事务正在进行某些操作,这些操作都是直接InnoDB自治的,不走server层,也就无法通过MDL所保护;

  • 当设置会话的autocommit变量为OFF时,执行LOCK TABLE tbname WRITE这样的操作会加表级的LOCK_X锁(ha_innobase::external_lock);

  • 对某个表空间执行discard或者import操作时,需要加LOCK_X锁(ha_innobase::discard_or_import_tablespace)。

LOCK_S
  • 在DDL的第一个阶段,如果当前DDL不能通过ONLINE的方式执行,则对表加LOCK_S锁(prepare_inplace_alter_table_dict);

  • 设置会话的autocommit为OFF,执行LOCK TABLE tbname READ时,会加LOCK_S锁(ha_innobase::external_lock)。

当客户端想对表进行写操作(插入、删除、更新等)时,需要先获得一个写锁,这会阻塞其他客户端对该表的所有读写操作。只有没有人执行写操作时,其他读取的客户端才能获得读锁,读锁之间不会相互阻塞。

表锁的冲突和兼容情况

XIXSIS
XConflictConflictConflictConflict
IXConflictCompatibleConflictCompatible
SConflictConflictCompatibleCompatible
ISConflictCompatibleCompatibleCompatible

从上面的描述我们可以看到LOCK_X及LOCK_S锁在实际的大部分负载中都很少会遇到。主要还是互相不冲突的LOCK_IS及LOCK_IX锁。一个有趣的问题是,每次加表锁时,却总是要扫描表上所有的表级锁对象,检查是否有冲突的锁。很显然,如果我们在同一张表上的更新并发度很高,这个链表就会非常长。

基于大多数表锁不冲突的事实,我们在RDS MYSQL中对各种表锁对象进行计数,在检查是否有冲突时,例如当前申请的是意向锁,如果此时LOCK_S和LOCK_X的锁计数都是0,就可以认为没有冲突,直接忽略检查。由于检查是在持有全局大锁lock_sys->mutex下进行的。在单表大并发下,这个优化的效果还是非常明显的,可以减少持有全局大锁的时间。

LOCK_AUTO_INC

AUTO_INC锁加在表级别,和AUTO_INC、表级S锁以及X锁不相容。锁的范围为SQL级别,SQL结束后即释放。

行锁

使用行级锁(row lock)可以最大程度地支持并发处理(也带来了最大的锁开销)。行级锁是在存储引擎而不是服务器中实现的。行锁依赖索引加锁,如果表没有索引,InnoDB会将锁加在隐藏的聚簇索引上。

Record Locks(行记录锁)

表示这个锁对象只是单纯的锁在记录上,不会锁记录之前的 GAP。比如利用唯一索引查询表中存在的一条记录。

Gap Locks(间隙锁)

间隙锁,锁定一个范围,但不包含这个范围中的行记录。

Next-Key Locks

上面两种锁的结合,锁定一个范围和这个范围内的行记录本身。目标是解决幻读问题(Phantom Problem)。

Record Locks演示

表结构

CREATE TABLE `tx_demo` (`id` bigint NOT NULL AUTO_INCREMENT,`age` int DEFAULT NULL,`name` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`),KEY `idx_age` (`age`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

数据

id

age

name

15

5

agc

16

8

agc

17

12

agc

19

13

agc

行记录锁演示

  1. 开始事务后执行SQL

    -- 开始事务后执行SQL
    select * from tx_demo where id = 19 for update;
  2. 查看持有锁的情况

    -- 查看持有锁的情况
    SELECT thread_id,INDEX_NAME,LOCK_TYPE,LOCK_MODE,LOCK_STATUS,LOCK_DATA
    FROMperformance_schema.data_locks;

  3. 持有锁的情况 

如上所示,该事务当前持有的锁是索引记录19,LOCK_MODE是X,REC_NOT_GAP。原因是该索引是唯一索引,并且该查询能检索出唯一一条数据。

Gap Locks演示
  1. 开始事务后执行SQL

    -- 开始事务后执行SQL
    select * from tx_demo where age = 10 for update;
  2. 查看持有锁的情况

    -- 查看持有锁的情况
    SELECT thread_id,INDEX_NAME,LOCK_TYPE,LOCK_MODE,LOCK_STATUS,LOCK_DATA
    FROMperformance_schema.data_locks;
  3. 持有锁的情况

 

如上所示,因为表中没有age=10的记录,因此Gap Locks锁定了(8,12)这个区间,注意,不包括12个索引记录。

Next-Key Locks演示
  1. 开始事务后执行SQL

    -- 开始事务后执行SQL
    select * from tx_demo where age = 8 for update;

  2. 查看持有锁的情况
    -- 查看持有锁的情况
    SELECT thread_id,INDEX_NAME,LOCK_TYPE,LOCK_MODE,LOCK_STATUS,LOCK_DATA
    FROMperformance_schema.data_locks;
  3. 持有锁的情况

 

如上所示,在索引idx_age上,这里涉及到的Record Locks是索引记录8,涉及到的Gap Locks有两个,分别是(5,8)、(8,12),因此结合起来就是Next-Key Locks (5,8]和Gap Locks(8,12)。 表中Next-Key Locks (5,8]的表示就是LOCK_DATA为8,16那一行,LOCK_MODE是X;表中Gap Locks(8,12)的表示就是LOCK_DATA为12,17那一行,LOCK_MODE是X,REC_NOT_GAP

LOCK_MODE的含义

MySQL表performance_schema.data_locks中LOCK_MODE列的含义

  • LOCK_MODE = X,说明是 X 型的 next-key 锁;

  • LOCK_MODE = X, REC_NOT_GAP,说明是 X 型的记录锁;

  • LOCK_MODE = X, GAP,说明是 X 型的间隙锁;

  • LOCK_MODE = AUTO_INC,说明是表级自增锁;

  • LOCK_MODE = UNKNOWN,说明是未知模式锁;

参考文档

https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

https://dev.mysql.com/doc/refman/8.0/en/performance-schema-data-locks-table.html

https://xiaolincoding.com/mysql/lock/show_lock.html#%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C

http://mysql.taobao.org/monthly/2016/01/01/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/499231.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在Window系统部署BUG管理软件并结合内网穿透实现远程管理本地BUG

文章目录 前言1. 本地安装配置BUG管理系统2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射本地服务3. 测试公网远程访问4. 配置固定二级子域名4.1 保留一个二级子域名5.1 配置二级子域名6. 使用固定二级子域名远程 前言 BUG管理软件,作为软件测试工程师的必备工具之一。在…

【数据分享】2001-2022年我国省市县镇四级的逐日平均降水量数据(免费获取\excel\shp格式)

降水数据是我们在各项研究中最常用的气象指标之一!之前我们给大家分享过来源于国家青藏高原科学数据中心发布的1961—2022年全国范围的逐日降水栅格数据(可查看之前的文章获悉详情)! 本次我们分享的是2001-2002年我国省市县镇四个…

Linux零基础快速入门

Linux的诞生 Linux创始人:林纳斯 托瓦兹 Linux 诞生于1991年,作者上大学期间 因为创始人在上大学期间经常需要浏览新闻和处理邮件,发现现有的操作系统不好用,于是他决心自己写一个保护模式下的操作系统,这就是Linux的原型,当时他…

方格分割644--2017蓝桥杯

1.用dfs解决,首先这题的方格图形就很像一个走迷宫的类型,迷宫想到dfs,最中心点视为起点,起点有两个小人在这个方格里面对称行动,直到走出迷宫(一个人走出来了另一个人就也走出来了,而走过的点会…

【力扣白嫖日记】550.游戏玩法分析IV

前言 练习sql语句,所有题目来自于力扣(https://leetcode.cn/problemset/database/)的免费数据库练习题。 今日题目: 550.游戏玩法分析IV 表:Activity 列名类型player_idintdevice_idintevent_datedategames_played…

Python 从文件中读取JSON 数据并解析转存

文章目录 文章开篇Json简介Json数据类型Json硬性规则Json数据转化网站Json和Dict类型转换json模块的使用Python数据和Json数据的类型映射json.dumps1.字典数据中含有**存在中文**2.json数据通过缩进符**美观输出**3.对Python数据类型中键进行**排序输出**4.json数据**分隔符的控…

Python调用ChatGPT API使用国内中转key 修改接口教程

大家好,我是淘小白~ 有的客户使用4.0的apikey ,直接使用官方直连的apikey消费很高,有一位客户一个月要消费2万,想使用4.0中转的apikey,使用中转的apikey 需要修改官方的openai库,下面具体说下。 1、首先确保安装的op…

代码随想录算法训练营第二十一天|530.二叉搜索树的最小绝对差、 501.二叉搜索树中的众数 、236. 二叉树的最近公共祖先

530.二叉搜索树的最小绝对差 题目链接/文章讲解: 代码随想录 视频讲解:二叉搜索树中,需要掌握如何双指针遍历!| LeetCode:530.二叉搜索树的最小绝对差_哔哩哔哩_bilibili 1.方法1 1.1分析及思路 了解到差值最小的数…

上门服务系统|上门服务小程序|上门服务软件开发

随着移动互联网技术的普及,上门服务小程序系统成为现代企业数字化转型的关键一环。这一系统为消费者提供了更加便捷、高效以及个性化的服务体验,同时也为企业带来了更广阔的商业机会。让我们来看看上门服务小程序系统的优势和功能。 首先,上门…

qt5与qt6的cmake区别

文章目录 使用cmake构建qt项目,坑很多。一是本身就麻烦,二是,确实坑,因为不同的qtcreator版本,选了不同的kits(套件) 生成的CMakeList.txt文件也不一样。 如果可以的话都选择Qt6的相关选项&…

lv19 多态 4

1 虚函数 虚函数&#xff08; 基类指针可指向派生类对象&#xff0c; 动态联编&#xff09; 先看示例&#xff0c;不加virtual&#xff0c;不认对象认指针。 #include <iostream>using namespace std;class A{ public:A(){ }~A(){ }void show(){cout<<"AAA…

尝鲜18倍速大模型Groq和世界第二AI Mistral(Le Chat)

01 尝鲜 中午,一边吃饭,一边尝试一下最新的AI:Groq,它使用了重新设计的LPU,据说比英伟达的GPU快了18倍。 运行了开源的Mixtral-8x7b模型,屏幕上的文字回复几乎是瞬间的,那种速度感,让人心跳加速。 接着,我尝试了来自欧洲的新贵——Mistral AI的Le Chat。 这个三天前…