MySQL的行锁、表锁、间隙锁详解(中)

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介: MySQL的行锁、表锁、间隙锁详解(中)

4 InnoDB锁

InnoDB与MyISAM的最大不同有两点

  • 支持事务
  • 采用行锁

行级锁和表级锁本来就有许多不同之处,另外,事务的引入也带来了一些问题。

查看Innodb行锁争用情况

image.png

如果发现争用比较严重,如Innodb_row_lock_waitsInnodb_row_lock_time_avg的值比较高

查询information_schema相关表来查看锁情况

image.png

设置Innodb monitors

进一步观察发生锁冲突的表,数据行等,并分析锁争用的原因

image.png

停止监视器

image.png

默认情况每15秒会向日志中记录监控的内容;

如果长时间打开会导致.err文件变得非常巨大;

所以确认原因后,要删除监控表关闭监视器,或者通过使用–console选项来启动服务器以关闭写日志功能

4.4 InnoDB的行锁

InnoDB支持以下两种类型的行锁

  • 共享锁(读锁S)
  • 若事务 T 对数据对象 A 加了 S 锁;

则事务 T 可以读 A 但不能修改 A;

其它事务只能再对它加 S 锁,而不能加 X 锁,直到 T 释放 A 上的 S 锁;

这保证了,其他事务可以读 A,但在事务 T 释放 S 锁之前,不能对 A 做任何修改操作.

排他锁(写锁X)

若事务 T 对数据对象A加 X 锁;

事务 T 可以读 A 也可以修改 A;

其他事务不能对 A 加任何锁,直到 T 释放 A 上的锁;

这保证了,其他事务在 T 释放 A 上的锁之前不能再读取和修改 A .

MySQL InnoDB默认行级锁

行级锁都是基于索引的,若一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住

为了允许行/表锁共存,实现多粒度锁,InnoDB还有两种内部使用的:

意向锁(Intention Locks)

这两种意向锁都是表级锁:

  • 意向共享锁(IS)
  • 事务打算给数据行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁
  • 意向排他锁(IX)
    事务打算给数据行加排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁
当前锁/是否兼容/请求锁 X IX S IS
X 冲突 冲突 冲突 冲突
IX 冲突 兼容 冲突 兼容
S 冲突 冲突 兼容 兼容
IS 冲突 兼容 兼容 兼容

如果一个事务请求的锁模式与当前锁兼容,InnoDB就请求的锁授予该事务,反之如果两者不兼容,该事务就要等待锁释放


意向锁是InnoDB自动加的,不需用户干预.

对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及及数据集加排他锁(X);

对于普通SELECT语句,InnoDB不会加任何锁.


对于SELECT语句,可以通过以下语句显式地给记录加读/写锁


共享锁(S)

image.png

排他锁(X)

image.png

共享锁语句主要用在需要数据依存关系时确认某行记录是否存在;

并确保没有人对这个记录UPDATE或DELETE.

但如果当前事务也需要对该记录进行更新,则很有可能造成死锁;

对于锁定行记录后需要进行更新操作的应用,应该使用排他锁语句.

此外还有自增锁(auto-in)和 lock tables/DDL等表级锁

查看锁:

SHOW ENGINE INNODB STATUS;

4.5 实例

4.5.1 Innodb共享锁

session_1 session_2
set autocommit=0,select * from actor where id =1 set autocommit=0,select * from actor where id =1
当前seesion对id为1的记录加入共享锁 select * from actor where id =1 lock in share mode



其他seesion仍然可以查询,并对该记录加入 select * from actor where id =1 lock in share mode
当前session对锁定的记录进行更新,等待锁 update。。。where id=1



当前session对锁定记录进行更新,则会导致死锁退出 update。。。where id=1
获得锁,更新成功


4.5.2 Innodb排他锁

session_1 session_2
set autocommit=0,select * from actor where id =1 set autocommit=0,select * from actor where id =1
当前seesion对id为1的记录加入for update 共享锁 select * from actor where id =1 for update



可查询该记录select *from actor where id =1,但是不能再记录共享锁,会等待获得锁select *from actor where id =1 for update
更新后释放锁 update。。。 commit
其他session,获得锁,得到其他seesion提交的记录

4.6 行锁的实现

行锁是通过给索引上的索引项加锁来实现。若没有索引,InnoDB将通过隐藏的聚簇索引来对记录加锁:

Record Locks

对索引项加锁

Gap lock

对索引项之的“间隙“,第一条记录前的”间隙“,或最后一条记录后的”间隙“,加锁

Next-key lock

前两种的组合,对记录及其前面的间隙加锁

行锁实现特点意味着:

若不通过索引条件检索数据,则Innodb将对表的所有记录加锁,和表锁一样。

记录锁(Record Locks)

record lock是对索引加的锁。例如,

SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;

阻止任何其他事务插入、更新或删除 t.c1=10 的行。


Record Locks总是锁定索引记录,即使表没有定义索引。对于这种情况,InnoDB 会创建一个隐藏的聚集索引并使用该索引进行记录锁定。


record lock的事务数据在 SHOW ENGINE INNODB STATUS 和 InnoDB 监视器输出中显示类似于以下内容:

RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`
trx id 10078 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000a; asc     ;;
 1: len 6; hex 00000000274f; asc     'O;;
 2: len 7; hex b60000019d0110; asc        ;;

间隙锁(Next-Key锁)

当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据的索引项加锁;

对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁).


举例来说,假如emp表中只有101条记录,其empid的值分别是1,2,…,100,101,下面的SQL:

InnoDB 不仅会对符合条件的 empid 值为 101 的记录加锁;

也会对 empid大于101(这些记录并不存在)的“间隙”加锁

image.png

作用

  • 防止幻读,以满足相关隔离级别的要求
    对于上例,若不使用间隙锁,如果其他事务插入 empid 大于 100 的任何记录,;
    那么本事务如果再次执行上述语句,就会发生幻读
  • 满足其恢复和复制的需要
    在使用范围条件检索并锁定记录时;
    InnoDB 这种加锁机制会阻塞符合条件范围内键值的并发插入,这往往会造成严重的锁等待;
    因此,在实际开发中,尤其是并发插入较多的应用;
    我们要尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件.
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
10月前
|
SQL AliSQL 关系型数据库
MYSQL的全局锁和表锁
本文介绍了MySQL中的锁机制,包括全局锁、表级锁及其应用场景。全局锁通过`Flush tables with read lock (FTWRL)`实现,主要用于全库逻辑备份,但会阻塞更新和结构变更操作。表级锁分为显式表锁(`lock tables`)和元数据锁(MDL),前者用于控制并发访问,后者自动加锁以确保读写正确性。文章还探讨了如何安全地为小表添加字段,建议通过设置DDL等待时间或使用MariaDB/AliSQL的NOWAIT/WAIT功能避免业务阻塞。这些方法有助于在高并发场景下优化数据库性能与安全性。
266 0
|
10月前
|
SQL 存储 关系型数据库
滴滴面试:明明 mysql 加的是 行锁,怎么就变 表锁 了?
滴滴面试:明明 mysql 加的是 行锁,怎么就变 表锁 了?
|
关系型数据库 MySQL 网络安全
如何排查和解决PHP连接数据库MYSQL失败写锁的问题
通过本文的介绍,您可以系统地了解如何排查和解决PHP连接MySQL数据库失败及写锁问题。通过检查配置、确保服务启动、调整防火墙设置和用户权限,以及识别和解决长时间运行的事务和死锁问题,可以有效地保障应用的稳定运行。
456 25
|
存储 关系型数据库 MySQL
MySQL进阶突击系列(06)MySQL有几种锁?| 别背答案,现场演示一下
本文详细解析了MySQL InnoDB存储引擎的锁机制,涵盖读锁、写锁、意向锁、记录锁、间隙锁和临键锁等8种锁类型。重点探讨了不同锁类型的加锁与释放方式,以及事务并发场景下的实战验证。通过具体示例,展示了在不同情况下锁的行为及其对事务的影响。文章还特别强调了锁的作用范围主要是索引,并解释了锁如何影响数据的读写操作。最后总结了并发事务中加锁规则,帮助读者深入理解MySQL的锁机制。
|
存储 关系型数据库 MySQL
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
779 1
|
存储 关系型数据库 MySQL
MySQL锁,锁的到底是什么?
【10月更文挑战第16天】MySQL 锁锁定的是与数据和资源相关的对象,其目的是为了保证数据的一致性、避免冲突,并在并发环境下合理协调事务或操作的执行。理解锁的对象和意义对于优化数据库性能、处理并发问题至关重要。
399 0
|
6月前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
455 158
|
6月前
|
关系型数据库 MySQL 数据库
自建数据库如何迁移至RDS MySQL实例
数据库迁移是一项复杂且耗时的工程,需考虑数据安全、完整性及业务中断影响。使用阿里云数据传输服务DTS,可快速、平滑完成迁移任务,将应用停机时间降至分钟级。您还可通过全量备份自建数据库并恢复至RDS MySQL实例,实现间接迁移上云。
|
6月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS费用价格:MySQL、SQL Server、PostgreSQL和MariaDB引擎收费标准
阿里云RDS数据库支持MySQL、SQL Server、PostgreSQL、MariaDB,多种引擎优惠上线!MySQL倚天版88元/年,SQL Server 2核4G仅299元/年,PostgreSQL 227元/年起。高可用、可弹性伸缩,安全稳定。详情见官网活动页。
1087 152
|
6月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎,提供高性价比、稳定安全的云数据库服务,适用于多种行业与业务场景。
847 156