浅谈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事务的隔离级别与MVCC
Apr 22 MySQL
MySQL 覆盖索引的优点
May 19 MySQL
探究Mysql模糊查询是否区分大小写
Jun 11 MySQL
MySQL 聚合函数排序
Jul 16 MySQL
SQL IDENTITY_INSERT作用案例详解
Aug 23 MySQL
SQL 聚合、分组和排序
Nov 11 MySQL
MySQL中varchar和char类型的区别
Nov 17 MySQL
MySQL的InnoDB存储引擎的数据页结构详解
Mar 03 MySQL
解决MySQL添加新用户-ERROR 1045 (28000)的问题
Mar 03 MySQL
MySQL实战记录之如何快速定位慢SQL
Mar 23 MySQL
MySQL 数据库范式化设计理论
Apr 22 MySQL
MySQL中dd::columns表结构转table过程及应用详解
Sep 23 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
php入门学习知识点四 PHP正则表达式基本应用
2011/07/14 PHP
PHP 输出URL的快捷方式示例代码
2013/09/22 PHP
浅谈php和js中json的编码和解码
2016/10/24 PHP
Laravel 5.4.36中session没有保存成功问题的解决
2018/02/19 PHP
javascript 学习之旅 (3)
2009/02/05 Javascript
JavaScript快速检测浏览器对CSS3特性的支持情况
2012/09/26 Javascript
JQuery的Ajax请求实现局部刷新的简单实例
2014/02/11 Javascript
JS设置cookie、读取cookie、删除cookie
2015/04/17 Javascript
bootstrap使用validate实现简单校验功能
2016/12/02 Javascript
详解照片瀑布流效果(js,jquery分别实现与知识点总结)
2017/01/01 Javascript
JavaScript中数组Array方法详解
2017/02/27 Javascript
微信小程序loading组件显示载入动画用法示例【附源码下载】
2017/12/09 Javascript
vue 2.x 中axios 封装的get 和post方法
2018/02/28 Javascript
vue中接口域名配置为全局变量的实现方法
2018/09/20 Javascript
vue中通过使用$attrs实现组件之间的数据传递功能
2019/09/01 Javascript
layui表单提交到后台自动封装到实体类的方法
2019/09/12 Javascript
在react中使用vue的状态管理的方法示例
2020/05/02 Javascript
Javascript实现秒表计时游戏
2020/05/27 Javascript
浅谈Vuex的this.$store.commit和在Vue项目中引用公共方法
2020/07/24 Javascript
[05:15]DOTA2英雄梦之声_第16期_灰烬之灵
2014/06/21 DOTA
[02:14]完美“圣”典2016风云人物:xiao8专访
2016/12/01 DOTA
[01:01:29]2018DOTA2亚洲邀请赛 4.4 淘汰赛 VP vs Liquid 第一场
2018/04/05 DOTA
python人人网登录应用实例
2014/09/26 Python
Python开发之快速搭建自动回复微信公众号功能
2016/04/22 Python
简单谈谈python中的Queue与多进程
2016/08/25 Python
django连接mysql配置方法总结(推荐)
2018/08/18 Python
解决django服务器重启端口被占用的问题
2019/07/26 Python
python利用faker库批量生成测试数据
2020/10/15 Python
css 元素选择器的简单实例
2016/05/23 HTML / CSS
存储过程和函数的区别
2013/05/28 面试题
《可爱的动物》教学反思
2014/02/22 职场文书
毕业生写求职信的要点
2014/03/04 职场文书
银行自荐信怎么写
2015/03/05 职场文书
《分数乘法》教学反思
2016/02/24 职场文书
Flask使用SQLAlchemy实现持久化数据
2021/07/16 Python
SQL Server中的游标介绍
2022/05/20 SQL Server