浅谈MySql update会锁定哪些范围的数据


Posted in MySQL onJune 25, 2022

1、背景

在项目中,我们经常使用到update语句,那么update语句会锁定表中的那些记录呢?此处我们通过一些简单的案例来模拟下。此处是我自己的一个理解,如果那个地方理解错了,欢迎指出

2、前置知识

2.1 数据库的隔离级别

mysql> show variables like 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)

2.2 数据库版本

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.28    |
+-----------+
1 row in set (0.00 sec)

2.3 数据库的存储引擎

mysql> show variables like '%storage_engine%';
+---------------------------------+-----------+
| Variable_name                   | Value     |
+---------------------------------+-----------+
| default_storage_engine          | InnoDB    |
| default_tmp_storage_engine      | InnoDB    |
| disabled_storage_engines        |           |
| internal_tmp_mem_storage_engine | TempTable |
+---------------------------------+-----------+
4 rows in set (0.01 sec)

2.4 锁是加在记录上还是索引上

锁是加在索引上,那如果表中没有建立索引,是否就是加在表上的呢?其实不是,也是加在索引的,会存在一个默认的。

Record locks always lock index records, even if a table is defined with no indexes. For such cases, InnoDB creates a hidden clustered index and uses this index for record locking

参考链接: https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

2.5 update...where加锁的基本单位是

UPDATE ... WHERE ... sets an exclusive next-key lock on every record the search encounters
此处可以理解加锁的单位是: next-key

2.6 行级锁

2.6.1 Record Locks

记录锁,即只会锁定一条记录。其实是锁定这条记录的索引。

A record lock is a lock on an index record. For example, SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE; prevents any other transaction from inserting, updating, or deleting rows where the value of t.c1 is 10.

2.6.2 Gap Locks

间隙锁,间隙锁是在索引记录之间的间隙上的锁,即锁定一个区间。前开后开区间,不包括记录本身。

间隙锁如果是使用单列唯一索引值进行更新的话,是会退化Record Lock

间隙锁的目的

  • 防止新的数据插入到间隙中
  • 防止已经存在的数据被更新到间隙中。

Gap locking is not needed for statements that lock rows using a unique index to search > for a unique row. (This does not include the case that the search condition includes only > some columns of a multiple-column unique index; in that case, gap locking does occur.)

2.6.3 Next-Key Locks

Next-Key Lock 是索引记录上记录锁索引记录之前间隙上的间隙锁的组合。也是锁定一个区间,前开后闭区间。包括记录本身。

如果索引值包括 1,5,10,30,那么next key 锁可能涵盖如下区间

(negative infinity, 1]
(1, 115
(5, 10]
(10, 30]
(30, positive infinity)

negative infinity指的是负无穷。positive infinity指的是正无穷。

2.6.4 测试锁表的表结构

create table test_record_lock
(
    id   int         not null comment '主键',
    age  int         null comment '年龄,普通索引',
    name varchar(10) null comment '姓名,无索引',
    constraint test_record_lock_pk
        primary key (id)
)
    comment '测试记录锁';

create index test_record_lock_age_index
    on test_record_lock (age);

2.6.5 表中的测试数据

mysql> select * from test_record_lock;
+----+------+--------+
| id | age  | name   |
+----+------+--------+
|  1 |   10 | 张三   |
|  5 |   20 | 李四   |
|  8 |   25 | 王五   |
+----+------+--------+
3 rows in set (0.00 sec)

2.7 查看数据库中当前的锁

select * from performance_schema.data_locks;

字段解释:

字段 解释
lock_type TABLE 锁是加在表上
  RECORD 锁加在记录上
lock_mode IX 意向排他锁
  X或者S next-key lock 
锁定记录本身和记录之前的间隙
  X,REC_NOT_GAP Record Lock 只锁记录自身
  S,REC_NOT_GAP Record Lock 只锁记录自身
  X,GAP gap lock
  X,INSERT_INTENTION 插入意向锁
lock_data 具体的某个数字 表示主键的值
  值,值 第一个值:普通索引的值
第二个值:主键值

疑问:X,GAP是否可以理解成X锁退化成了GAP锁。

3、测试数据加锁

3.1 唯一索引测试

此处适用单个字段的唯一索引,不适合多个字段的唯一索引

3.1.1 等值更新-记录存在

浅谈MySql update会锁定哪些范围的数据

解释:

加next-key lock,那么锁定的记录范围为 (1,5]。

因为是唯一索引,且查询的值存在,next-key lock退化成record lock,即最终只锁定了id=5的这一行数据。其余的数据不影响。

3.1.2 等值查询-记录不存在-01

浅谈MySql update会锁定哪些范围的数据

解释:

  • 加next-key lock,那么锁定的记录范围为 (5,8]。
  • 因为是唯一索引,且查询的值不存在,next-key lock退化成gap,即最终锁定的数据范围为(5,8)。其余的数据不影响。

3.1.3 等值更新-记录不存在-02

浅谈MySql update会锁定哪些范围的数据

3.1.4 范围更新

1、小于或等于最大临界值

浅谈MySql update会锁定哪些范围的数据

此时可以发现表中扫描到的记录都加上了next key lock(锁加在索引上)

2、大于或等于最小临界值

mysql> begin;
Query OK, 0 rows affected (0.01 sec)

mysql> update test_record_lock set name = 'aaa' where id >= 1;
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3  Changed: 3  Warnings: 0

mysql> select LOCK_TYPE,INDEX_NAME,LOCK_MODE,LOCK_DATA from performance_schema.data_locks;
+-----------+------------+---------------+------------------------+
| LOCK_TYPE | INDEX_NAME | LOCK_MODE     | LOCK_DATA              |
+-----------+------------+---------------+------------------------+
| TABLE     | NULL       | IX            | NULL                   |
| RECORD    | PRIMARY    | X,REC_NOT_GAP | 1                      |
| RECORD    | PRIMARY    | X             | supremum pseudo-record |
| RECORD    | PRIMARY    | X             | 8                      |
| RECORD    | PRIMARY    | X             | 5                      |
+-----------+------------+---------------+------------------------+
5 rows in set (0.01 sec)

此时只可向表中插入比最小临界值小的记录。

3、正常范围

浅谈MySql update会锁定哪些范围的数据

3.2 普通索引测试

3.2.1 等值更新-记录存在

浅谈MySql update会锁定哪些范围的数据

解释:

  • 先对普通索引age加上next-key lock,锁定的范围是(10,20]
  • next-key lock还会锁住本记录,因此在id索引的值等于5上加了Record Lock
  • 因为是普通索引并且值还存在,因此还会对本记录的下一个区间增加间隙锁 Gap Lock,锁定的范围为 (20,25)

3.2.2 等值更新-记录不存在

浅谈MySql update会锁定哪些范围的数据

解释:

  • 获取next-key lock 锁定的范围为 (10,20]
  • 因为需要更新的记录不存在,next-key lock退化成 gap lock,所以锁定的范围为(10,20)
  • 因为是普通索引且记录不存在,所以不需要再次查找下一个区间。

3.2.3 范围更新

浅谈MySql update会锁定哪些范围的数据

解释:

普通索引的范围更新,next-key-lock不回退化成 gap lock。

3.3 无索引更新

浅谈MySql update会锁定哪些范围的数据

从上图中可知,无索引更新数据表危险,需要谨慎处理。无索引更新,会导致全表扫描,导致将扫描到的所有记录都加上next-key lock

4、参考链接

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

到此这篇关于浅谈MySql update会锁定哪些范围的数据的文章就介绍到这了,更多相关MySql update锁定范围内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!


Tags in this post...

MySQL 相关文章推荐
mysql知识点整理
Apr 05 MySQL
Mysql systemctl start mysqld报错的问题解决
Jun 03 MySQL
解决Mysql的left join无效及使用的注意事项说明
Jul 01 MySQL
一篇文章看懂MySQL主从复制与读写分离
Nov 07 MySQL
SQL语法CONSTRAINT约束操作详情
Jan 18 MySQL
彻底解决MySQL使用中文乱码的方法
Jan 22 MySQL
千万级用户系统SQL调优实战分享
Mar 03 MySQL
MySQL的InnoDB存储引擎的数据页结构详解
Mar 03 MySQL
MySQL之MyISAM存储引擎的非聚簇索引详解
Mar 03 MySQL
MySql数据库 查询时间序列间隔
May 11 MySQL
MySQL控制流函数(-if ,elseif,else,case...when)
Jul 07 MySQL
MySql统计函数COUNT的具体使用详解
Aug 14 MySQL
MySQL导致索引失效的几种情况
Jun 25 #MySQL
Mysql中的触发器定义及语法介绍
Jun 25 #MySQL
MySQL数据库配置信息查看与修改方法详解
Jun 25 #MySQL
SQL语句中EXISTS的详细用法大全
Jun 25 #MySQL
MySQL约束(创建表时的各种条件说明)
Jun 21 #MySQL
MySQL数据库实验实现简单数据库应用系统设计
Jun 21 #MySQL
MySQL数据库表约束讲解
Jun 21 #MySQL
You might like
轻松入门: 煮好咖啡的七个诀窍
2021/03/03 冲泡冲煮
PHP 模板高级篇总结
2006/12/21 PHP
php foreach 参数强制类型转换的问题
2010/12/10 PHP
openflashchart 2.0 简单案例php版
2012/05/21 PHP
php与python实现的线程池多线程爬虫功能示例
2016/10/12 PHP
PHP+JS实现的实时搜索提示功能
2018/03/13 PHP
PHP echo()函数讲解
2019/02/15 PHP
关于Anemometer图形化显示MySQL慢日志的工具搭建及使用的详细介绍
2020/07/13 PHP
JavaScript 动态生成方法的例子
2009/07/22 Javascript
关于Aptana Studio生成自动备份文件的解决办法
2009/12/23 Javascript
jQuery(非HTML5)可编辑表格实现代码
2012/12/11 Javascript
JavaScript中最容易混淆的作用域、提升、闭包知识详解(推荐)
2016/09/05 Javascript
JavaScript的变量声明提升问题浅析(Hoisting)
2016/11/30 Javascript
nodejs基础应用
2017/02/03 NodeJs
Node.js环境下Koa2添加travis ci持续集成工具的方法
2017/06/19 Javascript
Vuex利用state保存新闻数据实例
2017/06/28 Javascript
浅谈vue.use()方法从源码到使用
2019/05/12 Javascript
vue form表单post请求结合Servlet实现文件上传功能
2021/01/22 Vue.js
[02:07]2018DOTA2亚洲邀请赛主赛事第三日五佳镜头 fy极限反杀
2018/04/06 DOTA
python实现聊天小程序
2018/03/13 Python
python如何定义带参数的装饰器
2018/03/20 Python
详谈python3中用for循环删除列表中元素的坑
2018/04/19 Python
python实现Dijkstra静态寻路算法
2019/01/17 Python
用python生成(动态彩色)二维码的方法(使用myqr库实现)
2019/06/24 Python
Python-numpy实现灰度图像的分块和合并方式
2020/01/09 Python
python新手学习可变和不可变对象
2020/06/11 Python
详解Pycharm与anaconda安装配置指南
2020/08/25 Python
Python 实现3种回归模型(Linear Regression,Lasso,Ridge)的示例
2020/10/15 Python
python字符串拼接+和join的区别详解
2020/12/03 Python
解决pycharm导入numpy包的和使用时报错:RuntimeError: The current Numpy installation (‘D:\\python3.6\\lib\\site-packa的问题
2020/12/08 Python
中专药剂专业应届毕的自我评价
2013/12/27 职场文书
项目计划书范文
2014/01/09 职场文书
中专生自荐信
2014/06/25 职场文书
青年志愿者活动方案
2014/08/17 职场文书
幼儿教师自我剖析材料
2014/09/29 职场文书
vue实现简单数据双向绑定
2021/04/28 Vue.js