本文介绍: MySQL中的锁,按照锁的粒度分,分为以下三类全局锁:锁定数据库中的所有表。表级锁:每次操作锁住整张表。行级锁:每次操作锁住对应行数据。

目录

前言

全局锁

表级锁

表锁

元数据锁(MDL)

意向锁

行级锁

行锁

行锁演示

间隙锁/临界锁

演示


前言

MySQL中的锁,按照锁的粒度分,分为以下三类

全局

全局锁就是对整个数据库实例加锁加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,以及更新操作事务提交语句都将被阻塞

其典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。

具体语句为

-- 添加全局锁
flush tables with read lock;
-- 开始备份
mysqldump -r用户名 -p密码 数据库名>保存文件名称.sql
-- 解锁
unlock tables;

全局锁特点

但也存在阻塞而是基于快照可以实现备份的语句

mysqldump --single-transaction -u用户名 -p密码 数据库名>保存文件名称.sql

表级锁

每次操作所著整张表,锁定粒度大,发生所冲突概率最高,并发度最低。

对于表级锁,主要分为以下三类:

表锁

对于表锁可以分为两类

基本语法

-- 加锁
lock tables 表名read/write;
-- 释放锁
unlock tables / 客户端断开连接

读锁特点

写锁特点

  • 自身既可以读也可以写。
  • 其他客户端不能读也不能写,会直接阻塞

元数据锁(MDL)

MDL加锁过程系统自动控制,无需显式使用,在访问一张表的时候会自动加上。MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。主要是为了避免DML与DDL冲突,保证读写正确性。

在MySQL5.5中引入了MDL,当对一张表进行增删改查的时候,加MDL读锁(共享),当对表结构进行变更操作的时候,加MDL写锁(排他)。

对应SQL

类型

select

SHARED_READ

insertupdatedelete

SHARED_WRITE

alter table

EXCLUSIVE

共享读与共享写都属于共享锁,他们两个互相兼容并于排他锁互斥

查看数据库中元数据锁信息

select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema.metadata_locks ;

意向锁

意向锁是为了避免DML数据库操作语句在执行过程中,出现行锁与表锁冲突通过意向锁可以在创建表锁时不需要检查每行数据是否有行锁,从而减少表锁检查所带来的性能消耗。

没有使用意向锁之前,客户端A给表中加了行锁,客户端B要给表加表锁,过程如下

首先客户端A开启一个事务,在事务中对表中的数据进行增删改查,在执行增删改时,会对表中的这些数据加一个行锁,这时客户端B想在表中加一个表锁,客户端B在添加表锁前,先会去检查当前表中一行数据是否有行锁,如果没有则会去添加表锁。

也就是说,不使用意向锁的话。客户端向表加锁需要遍历整张表,当表数据量很大时,效率很低。

当有了意向锁之后,客户端A给表中加了行锁,客户端B要给表加表锁,过程如下

首先客户端A开启一个事务,在事务中对表的数据进行增删改查,对数据添加行锁的同时,又会给表添加一个意向锁,这时客户端B想要在表中加一个表锁,客户端B就会根据客户端A加的意向锁来判断是否可以成功添加表锁,并且不会再逐行检查数据是否有行锁,效率得到大幅度提升。

简单来说,意向锁相当于一个声明,而不是一个真正的锁,根据这个声明,添加表锁时就有了参考依据,因此不需要逐行判断是否可以添加表锁,从而避免了行锁与表锁产生的冲突

意向锁的分类

意向共享锁可以与表锁中表共享读锁(read)兼容,但是与表锁中的表独占写锁(write互斥,当表中存在一个意向共享锁时,我们可以为表正常设置一个读锁,但是不能设置为写锁,当为表设置写锁时,就会处于阻塞状态,只有当事务提交后,写锁才能正常执行

意向排它锁既与表共享读锁排斥又与表独占写锁排斥,当表中有意向排它锁时,即不可以设置表读锁,也不可以设置为表写锁。

当事务提交后,意向共享锁、意向排它锁都自己释放锁(说是释放,其实可以理解为将标记清空),被阻塞的操作此时才能被执行

行级锁

行级锁,每次操作锁住对应行数据。锁定粒度最小,发生锁冲突概率最低,并发度最高。应用在InnoDB存储引擎中。

InnoDB的数据是基于索引组织的,行锁是通过索引上的索引项加锁来实现的,而不是对记录加的锁。对于行级锁,主要分为以下三类:

行锁(Record Lock):锁定单个行记录的锁,防止其他事务对此行进行updatedelete。在读已提交、可重复隔离级别下都支持

间隙锁(Gap Lock):锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert,产生幻读。在可重复隔离级别下都支持

临键锁(Next-Key Lock):行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap。在可重复读隔离级别支持

行锁

InnoDB实现了以下两种类型的行锁:

  • 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁。
  • 排他锁(X):允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁。

锁兼容情况如下

共享锁

排他锁

共享锁

兼容

互斥

排他锁

互斥

互斥

加锁情况如下

SQL

行锁类型

说明

insert

排他锁

自动加锁

update

排他锁

自动加锁

delete

排他锁

自动加锁

select

不加锁

select……lock in share mode

共享锁

需要手动select之后添加local in share mode

select ……for update

排他锁

需要手动select之后加for update

行锁演示

默认情况下,lnnoDB在可重复读事务隔离级别运行,InnoDB使用临键锁进行搜索索引扫描,以防止幻读。

查看行锁情况的SQL语句

select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks ;

现在存在一个主键iduser表,username没有创建索引

一个客户端开启事务,并进行查询。另一个客户端查看行锁数据

此时我们可以看到,MySQL没有对select语句进行加锁。接下来我们手动对select语句加锁

由于行锁中的共享锁是互相兼容的,因此我也可以再另一个客户端进行select语句,此时锁记录表中出现两条锁记录。

当事务提交后,事务涉及到锁也会释放

接下来我们测试update语句

接下来测试对非索引的字段进行条件判断,观察添加的是什么锁

因此我们可以知道,当对没有索引的字段进行条件查询时,行级锁会升级为表锁。

间隙锁/临界锁

默认情况下,InnoDB在可重复读事务隔离级别运行,lnnoDB使用间隙锁锁进行搜索和索引扫描,以防止幻读。

  1. 索引上的等值查询(唯一索引),给不存在的记录加锁时,优化为间隙锁。
  2. 索引上的等值查询(普通索引),向右遍历最后一个值不满足查询需求时,临键锁退化为间隙锁
  3. 索引上的范围查询(唯一索引),会访问到不满足条件的第一个值为止。

注意:间隙锁唯一目的是防止其他事务插入间隙。间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁。

演示

展示第一种情况,给不存在的记录加锁。

加下来展示第二种情况,我添加了一个age字段,并创建了普通索引

另一个客户端插入对应锁住范围时会阻塞,而插入其他范围可以正常执行。

接下来展示第三种情况,对唯一索引的范围查找

原文地址:https://blog.csdn.net/zmbwcx/article/details/134698709

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_15189.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注