searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

MySQL的锁

2024-09-18 09:21:44
4
0

一、概述

MySQL InnoDB存储引擎,实现的是基于多版本的并发控制协议​——MVCC (​Multi-Version Concurrency Control​) (注:与MVCC相对的,是基于锁的并发 控制,​Lock-Based Concurrency Control​)。 MVCC相较于锁并发控制,优势在于:读不加锁,读写不冲突​​。在读多写少的OLTP应用,极大增加了系统并发。这也是当前几乎所有的关系型数据库系统都支持MVCC。

二、快照读&当前读

快照读,读取的是记录的可见版本 (有可能是历史版本),不加锁。当前读,读取的是记录的最新版本,并且,当前读返回的记录 ,加锁。

select * from table where xxx;
  • 当前读
-- S锁(共享锁)
-- 8.0以后可以使用 select * from tabel where xxx for share;
select * from tabel where xxx lock in share mode;
-- X锁(排他锁)
select * from table where xxx for update;
insert into xxx;
update table set xxx;
delete from table where xxx;

将插入、更新、删除这些都归为当前读是因为操作之前,都会有当前读的操作。

三、MySQL的锁类型

默认情况下,数据库中的锁都可以自动获取,但是也可以手动为数据进行加锁。在 MySQL 里,根据加锁的范围,可以分为全局锁、表级锁和行锁三类。

QQ_1726035936700.png

共享锁(S锁)满足读读共享,读写互斥。排他锁(X锁)满足写写互斥、读写互斥。

QQ_1726036289302.png

意向锁是一种锁的层次结构,当一个事务需要设置行锁时,会先获取意向锁,表明该事务对该行进行加锁的操作,同时其他事务可以获取表级别的锁。

QQ_1726036328064.png

1. 全局锁

# 以只读去锁住整个数据库
flush tables with read lock;
# 解锁
unlock tables;

2.表级锁

MDL---元数据锁

select * from performance_schema.metadata_locks;

3.行级锁

行级锁的实现:InnoDB 通过给索引上的索引项加锁的方式,而非记录​实现行级锁,​与Oracle对数据行加锁的方式不一样,InnoDB这样的加锁方式意味着,通过索引条件检索数据,innodb才使用行级锁,否则,将使用表锁。具体来说,InnoDB 实现了三种行级锁的算法:记录锁(Record Lock)、间隙锁(Gap Lock)和 Next-key 锁(Next-key Lock, record和gap lock的组合)又称临键锁。

行级锁,是通过索引检索的角度去加锁。

record锁

record锁永远都是锁定索引记录,锁定非聚集索引会先锁定聚集索引(那么就会出现 意向锁IX、X)。如果表中没有定义索引,InnoDB 默认为表创建一个隐藏的聚簇索引,并且使用该索引锁定记录。

Gap锁

锁定的是索引记录之间的间隙。例如,c1为唯一索引,SELECT * FROM t WHERE c1 BETWEEN 1 and 10 FOR UPDATE; 会阻止其他事务将 1 到 10 之间的任何值插入到 c1 字段中,即使该列不存在这样的数据;因为这些值都会被锁定。

next-key锁

record和Gap的组合。

4.语句加锁实现分析

create database if not exists test ;
use test;

CREATE TABLE `t` (
  `id` int NOT NULL,
  `name` varchar(10) DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

insert into t values(1, 'A-Alice', 100), (3, 'E-Bob', 200), (6, 'Z-Cak', 300)

1.在主键上的动作

略,较简单。

2. 在唯一键操作

等值查询的数据存在
会在唯一索引上加record锁,在对应的主键加record锁。(非唯一/唯一索引的叶子节点数据是主键,主键的叶子节点是数据页)。唯一索引record锁,可以让唯一索引跟主键的对应关系在锁期间不被篡改。锁唯一键,则保证查看数据的链路(唯一索引--->主键--->数据)得到的结果在锁定期间不被篡改。

等值查询不存在
只在唯一索引上加GAP锁。保证不会突然出现等值的记录。

范围查询存在/不存在

(唯一键, 主键)的组合排序,在这个组合上的gap锁、next-key锁。以及primary key上的record锁。

3.在非唯一键上的动作

等值查询的数据不存在

锁的动作是根据(查询使用的非唯一键,主键)这样的组合值排序来设置点位,从而判断点位之间的gap,并来设置gap锁。

等值查询,值存在

​操作动作:name为非唯一索引,查询的name='E-Bob'记录存在

-- 开启事务
begin;
update test.t set age=age + 3 where name='E-Bob';
-- 最后回滚
rollback;

锁情况

QQ_1726037551741.png

QQ_1726037568123.png

以上,第1行IX写表意向锁。第2行,next-key锁,锁定范围( ('A-Alice', 1), ('E-Bob', 3) ]。第3行,行锁主键id=3。第4行,间隙锁,( ('E-Bob', 3), ('Z-Cak', 6) )

在非索引上的动作

非索引操作,无论等值还是范围查询,需要在主键上加next-key锁。锁住表的所有范围,即我们所说的“锁表”。

0条评论
作者已关闭评论
尹****华
3文章数
0粉丝数
尹****华
3 文章 | 0 粉丝
尹****华
3文章数
0粉丝数
尹****华
3 文章 | 0 粉丝
原创

MySQL的锁

2024-09-18 09:21:44
4
0

一、概述

MySQL InnoDB存储引擎,实现的是基于多版本的并发控制协议​——MVCC (​Multi-Version Concurrency Control​) (注:与MVCC相对的,是基于锁的并发 控制,​Lock-Based Concurrency Control​)。 MVCC相较于锁并发控制,优势在于:读不加锁,读写不冲突​​。在读多写少的OLTP应用,极大增加了系统并发。这也是当前几乎所有的关系型数据库系统都支持MVCC。

二、快照读&当前读

快照读,读取的是记录的可见版本 (有可能是历史版本),不加锁。当前读,读取的是记录的最新版本,并且,当前读返回的记录 ,加锁。

select * from table where xxx;
  • 当前读
-- S锁(共享锁)
-- 8.0以后可以使用 select * from tabel where xxx for share;
select * from tabel where xxx lock in share mode;
-- X锁(排他锁)
select * from table where xxx for update;
insert into xxx;
update table set xxx;
delete from table where xxx;

将插入、更新、删除这些都归为当前读是因为操作之前,都会有当前读的操作。

三、MySQL的锁类型

默认情况下,数据库中的锁都可以自动获取,但是也可以手动为数据进行加锁。在 MySQL 里,根据加锁的范围,可以分为全局锁、表级锁和行锁三类。

QQ_1726035936700.png

共享锁(S锁)满足读读共享,读写互斥。排他锁(X锁)满足写写互斥、读写互斥。

QQ_1726036289302.png

意向锁是一种锁的层次结构,当一个事务需要设置行锁时,会先获取意向锁,表明该事务对该行进行加锁的操作,同时其他事务可以获取表级别的锁。

QQ_1726036328064.png

1. 全局锁

# 以只读去锁住整个数据库
flush tables with read lock;
# 解锁
unlock tables;

2.表级锁

MDL---元数据锁

select * from performance_schema.metadata_locks;

3.行级锁

行级锁的实现:InnoDB 通过给索引上的索引项加锁的方式,而非记录​实现行级锁,​与Oracle对数据行加锁的方式不一样,InnoDB这样的加锁方式意味着,通过索引条件检索数据,innodb才使用行级锁,否则,将使用表锁。具体来说,InnoDB 实现了三种行级锁的算法:记录锁(Record Lock)、间隙锁(Gap Lock)和 Next-key 锁(Next-key Lock, record和gap lock的组合)又称临键锁。

行级锁,是通过索引检索的角度去加锁。

record锁

record锁永远都是锁定索引记录,锁定非聚集索引会先锁定聚集索引(那么就会出现 意向锁IX、X)。如果表中没有定义索引,InnoDB 默认为表创建一个隐藏的聚簇索引,并且使用该索引锁定记录。

Gap锁

锁定的是索引记录之间的间隙。例如,c1为唯一索引,SELECT * FROM t WHERE c1 BETWEEN 1 and 10 FOR UPDATE; 会阻止其他事务将 1 到 10 之间的任何值插入到 c1 字段中,即使该列不存在这样的数据;因为这些值都会被锁定。

next-key锁

record和Gap的组合。

4.语句加锁实现分析

create database if not exists test ;
use test;

CREATE TABLE `t` (
  `id` int NOT NULL,
  `name` varchar(10) DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

insert into t values(1, 'A-Alice', 100), (3, 'E-Bob', 200), (6, 'Z-Cak', 300)

1.在主键上的动作

略,较简单。

2. 在唯一键操作

等值查询的数据存在
会在唯一索引上加record锁,在对应的主键加record锁。(非唯一/唯一索引的叶子节点数据是主键,主键的叶子节点是数据页)。唯一索引record锁,可以让唯一索引跟主键的对应关系在锁期间不被篡改。锁唯一键,则保证查看数据的链路(唯一索引--->主键--->数据)得到的结果在锁定期间不被篡改。

等值查询不存在
只在唯一索引上加GAP锁。保证不会突然出现等值的记录。

范围查询存在/不存在

(唯一键, 主键)的组合排序,在这个组合上的gap锁、next-key锁。以及primary key上的record锁。

3.在非唯一键上的动作

等值查询的数据不存在

锁的动作是根据(查询使用的非唯一键,主键)这样的组合值排序来设置点位,从而判断点位之间的gap,并来设置gap锁。

等值查询,值存在

​操作动作:name为非唯一索引,查询的name='E-Bob'记录存在

-- 开启事务
begin;
update test.t set age=age + 3 where name='E-Bob';
-- 最后回滚
rollback;

锁情况

QQ_1726037551741.png

QQ_1726037568123.png

以上,第1行IX写表意向锁。第2行,next-key锁,锁定范围( ('A-Alice', 1), ('E-Bob', 3) ]。第3行,行锁主键id=3。第4行,间隙锁,( ('E-Bob', 3), ('Z-Cak', 6) )

在非索引上的动作

非索引操作,无论等值还是范围查询,需要在主键上加next-key锁。锁住表的所有范围,即我们所说的“锁表”。

文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0