Mysql数据库死锁实战-锁的基础知识
文章目录
- 目标
- 基础知识
- 事务的演进
- 并发事务
- 方式一:逐个执行
- 方式二:排他锁(互斥锁)
- 方式三: 读写锁
- 方式四:MVCC(多版本并发控制)
- 隔离级别
- 事务的分类
- Innodb 锁的基础定义
- 共享锁(S)和 独占锁(X)
- 意向锁(I锁)
- 记录锁(RecordLock)
- 间隙锁(GapLock)
- Next-key锁
- 插入意向锁(Insert Intention Locks)
- 事务隔离级别和锁的关系
- 提出几个问题?
- 加锁过程分析
目标
了解mysql innodb 引擎下锁机制
常见死锁问题排查和解决
参考:MySQL批量更新数据
详解 MySql InnoDB 中意向锁的作用
MySQL锁释放时机(事务)
以下实例演示基于 MySQL 5.7.33版本 Innodb引擎
mysql 5.7 版本官方文档:https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-transaction-model.html 理论内容很多借鉴官方文档的描述
Mysql数据库死锁实战:分四篇
- 锁的基础知识
- 死锁演示1:排他锁的相互等待
- 死锁演示2:共享锁与互斥锁排队等待
- 死锁总结
先提出一个问题,可以思考下:
- Mysql事务之间出现死锁,会造成什么影响?
基础知识
事务的演进
事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)事务-百度百科
在关系型数据库中(mysql)中,实现事务要满足四个特性(ACID),原子性,持久性,隔离性,一致性。我们期望通过事务操作,来保证数据的完整性。比如执行的一次事务中的sql要么都成功,要么都不成功(undo log 回滚),如果成功执行了事务,数据都能正确持久化到磁盘中,无论后续发生了数据库实例停止服务,或者服务器停电宕机(redo log ,双写缓存区)。并且要保证成功落地的数据,要符合数据库表定义的约束,比如符合唯一索引要求,主键唯一等的约束要求。还要保证多个事务操作同时并发,之间执行的sql 操作是隔离的,不能受其他事务中执行的sql 语句影响(隔离级别和锁)。
为了实现四个特性,mysql提供了回滚日志(undo log)保证原子性,bin log 日志,重做日志(redo log)和双写缓存区保证持久性,锁机制和MVCC保证事务隔离。一致性则由三种特性一起保证。采用了WAL (先写日志,再写磁盘的逻辑),
画外音: 在mysql中, 事务通常是一条sql或者一组sql组成。
并发事务
并发事务指多个事务同时执行。会带来四个问题:
更新丢失
当两个或多个事务更新同一行记录,会产生更新丢失现象。可以分为回滚覆盖和提交覆盖。
回滚覆盖:一个事务回滚操作,把其他事务已提交的数据给覆盖了。
提交覆盖:一个事务提交操作,把其他事务已提交的数据给覆盖了。脏读
一个事务获取到另一个事务修改没有提交的数据。
不可重复读
一个事务中多次读取同一行数据,后面的获取的和前面读取的不一致。
幻读
一个事务中多次按相同的条件查询,结果不一致。后续查询的结果和前面查询的结果不一致,多了几行或者少几行。
为了解决这些问题,提出了一些办法。
画外音:可以参照Java 多线程操作同一个数据,出现的并发问题的解决方式(串行化,锁)来理解mysql 中的一些做法,大同小异。
方式一:逐个执行
最简单的方式,让所有事务排队,逐个执行,保证一次只执行一个事务,没有并发事务的问题。
方式二:排他锁(互斥锁)
引入锁机制,对于事务中操作相同数据时,采用互斥锁。先获取锁的事物执行,释放后,其他事务获取锁再执行。
方式三: 读写锁
优化互斥锁,区分读写操作,多个事务对同一数据的读取操作不阻塞。多个事务之间的读写,写读,写写还是采用互斥锁。
方式四:MVCC(多版本并发控制)
进一步优化读写锁,使得多个事务并行操作时,读读之间不加锁。读写和写读也不进行阻塞。只有写写的情况阻塞。事务一对数据读取时,copy一个副本供其他事务读取数据时使用。
在SQL92定制的标准中提出了事务隔离级别,相当于事务并发控制的整体解决方案,本质上是对锁和MVCC使用的封装,隐藏了底层细节。那么mysql也是基于此标准,提供了事务隔离级别的实现。
隔离级别
锁是数据库实现并发控制的基础,事务隔离性是采用锁来实现,对相应操作加不同的锁,就可以防止其他事务同时对数据进行读写操作。
在mysql可重复读级别,实际上是可以解决幻读问题的。因为对于数据行索引的加锁,优先使用next key锁,对数据行和间隙进行加锁,锁住索引间隙,防止有数据的插入或者删除。官方文档:https://dev.mysql.com/doc/refman/5.7/en/innodb-next-key-locking.html
事务的分类
隐性事务
在InnoDB中,所有用户活动都发生在事务内部。如果启用了自动提交(
autocommit
)模式,则每个SQL语句各自形成一个事务。自动提交模式是默认开启的。在执行DML语句(insert,update,delete)时,事务自动开启,提交或者回滚。mysql> show variables like 'autocommit'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+ 1 row in set
显性事务
如果需要自定义事务,使用多个语句,请使用SQL语句集autocommit=0关闭autocommit,并根据需要使用COMMIT或ROLLBACK结束每个事务。在开发过程中,通常会使用 @Transactional 来开启事务,来执行多条业务sql。
-- 常见自定义事务 -- 开启事务 或者 mysql> SET autocommit=0; mysql> START TRANSACTION; -- 执行业务sql mysql> insert into xx values('xx'); -- 提交事务 mysql> COMMIT; -- 或者回滚事务 mysql> ROLLBACK;
Innodb 锁的基础定义
共享锁(S)和 独占锁(X)
InnoDB实现了标准的行级锁定,其中有两种类型的锁:共享(S)锁和独占(X)锁。
共享锁:允许持有该锁的事务读取一行,只允许读取数据,不能修改。允许其他事务对该记录追加S锁,不允许其他事务对该记录追加X锁,必须等待所有的共享锁释放。
独占锁:允许持有锁的事务读取,更新或删除行。其他事务不能对该记录不能读取,修改或者删除。
意向锁(I锁)
意向锁是表级锁,用于指示事务稍后对表中的行需要加上哪种类型的锁(共享或独占)。有两种类型的意向锁:
意向共享锁(IS):表示事务打算在表中的各个行上设置共享锁。
意向独占锁(IX):表示事务打算在表中的各个行上设置独占锁。
意向锁定协议如下:
在事务可以获取表中某行的共享锁之前,它必须首先获取表上的IS锁或更高级别的锁。
在事务可以获取表中某行的独占锁之前,它必须首先获取表上的IX锁。
下表总结了表级锁类型兼容性。
特别注意:下列指的共享锁和互斥锁,都是表锁。意向锁不会与行级的共享 / 排他锁互斥!!!
X
|
IX
|
S
|
IS
|
|
---|---|---|---|---|
X
|
冲突 | 冲突 | 冲突 | 冲突 |
IX
|
冲突 | 兼容的 | 冲突 | 兼容的 |
S
|
冲突 | 冲突 | 兼容的 | 兼容的 |
IS
|
冲突 | 兼容的 | 兼容的 | 兼容的 |
如果请求事务与现有锁兼容,则会将锁授予该事务,但如果它与现有锁冲突,则不会授予该事务。事务将等待冲突的现有锁被释放。如果锁请求与现有锁冲突,并且由于可能导致死锁而无法授予,则会发生错误。
意图锁不会阻止除完整表请求以外的任何请求(例如,锁定表…写入)。意向锁的主要用途是显示有人正在锁定一行,或打算锁定表中的一行。
下面内容,请注意各个锁支持的事务隔离级别,经常有文章说,在允许幻读和不可重复读的情况下,尽量使用RC的隔离级别,避免gap lock造成的死锁。
记录锁(RecordLock)
记录锁是索引记录上的锁。记录锁始终锁定索引记录,即使定义的表没有索引。对于这种情况,InnoDB会创建一个隐藏的聚集索引,并使用该索引进行记录锁定。innodb 的锁都是基于索引的锁,设计一个好的索引,有助于减少锁竞争,提升mysql并发能力。(RC、RR隔离级别都支持)
-- 使用 SHOW ENGINE INNODB STATUS 查看锁信息,下面是排他锁的示例
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 00: len 4; hex 8000000a; asc ;;1: len 6; hex 00000000274f; asc 'O;;2: len 7; hex b60000019d0110; asc ;;
SHOW ENGINE INNODB STATUS
显示来自标准InnoDB
监视器的有关InnoDB
存储引擎状态的大量信息
间隙锁(GapLock)
间隙锁是对索引记录之间间隙的锁定,或对第一条索引记录之前或最后一条索引记录之后的间隙的锁定。使用唯一索引锁定行以搜索唯一行的语句不需要间隙锁定。(范围锁,RR隔离级别支持)。间隙锁可以共存。一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁。共享和排他间隙锁之间没有区别。它们彼此不冲突,并且执行相同的功能。
特别注意:不同的事务可以在间隙上持有冲突的锁。例如,事务 A 可以在间隙上持有共享间隙锁(间隙 S 锁),而事务 B 在同一间隙上持有排他间隙锁(间隙 X 锁)。允许冲突间隙锁的原因是,如果从索引中清除记录,则必须合并不同事务在记录上持有的间隙锁。
Next-key锁
next-key 锁是索引记录上的记录锁和索引记录之前的间隙上的间隙锁的组合。InnoDB执行行级锁定的方式是,当它搜索或扫描表索引时,它会对遇到的索引记录设置共享或独占锁定。因此,行级锁实际上是索引记录锁。索引记录上的下一个键锁也会影响该索引记录之前的“间隙”。也就是说,下一个键锁是索引记录锁加上索引记录前面的间隙上的间隙锁。如果一个会话在索引中的记录R上具有共享或独占锁,则另一个会话不能在紧靠索引顺序中的R之前的间隙中插入新的索引记录。(记录锁+范围锁,RR隔离级别支持)
假设一个索引包含值 10、11、13 和 20。该索引可能的 next-key 锁涵盖以下区间,其中圆括号表示排除区间端点,方括号表示包含端点:
有些文章会写,Gap间隙的区间是一个左开右闭的空间,或者上界开,下界毕的区间。
(负无穷大negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity正无穷大)
用于下一个键锁定事务数据出现类似于在下面SHOW ENGINE INNODB STATUS和 InnoDB的监视器 输出:
RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`
trx id 10080 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 00: len 4; hex 8000000a; asc ;;1: len 6; hex 00000000274f; asc 'O;;2: len 7; hex b60000019d0110; asc ;;
插入意向锁(Insert Intention Locks)
插入意图锁是一种间隙锁,由 INSERT
行插入之前操作。此锁表示插入意图,如果插入同一索引间隙的多个事务未插入间隙内的相同位置,则它们无需相互等待。假设存在值为 4 和 7 的索引记录。 分别尝试插入值 5 和 6 的单独事务,在获得插入行的排他锁之前,每个事务都使用插入意向锁锁定 4 和 7 之间的间隙,但不会相互阻塞,因为行是不冲突的。
用于插入意图锁定事务数据出现类似于在下面 SHOW ENGINE INNODB STATUS
和 InnoDB的监视器 输出:
RECORD LOCKS space id 31 page no 3 n bits 72 index `PRIMARY` of table `test`.`child`
trx id 8731 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 00: len 4; hex 80000066; asc f;;1: len 6; hex 000000002215; asc " ;;2: len 7; hex 9000000172011c; asc r ;;...
需要插入意向锁的目的,是为了提升并发插入数据时的并发能力。
事务隔离级别和锁的关系
InnoDB
使用不同的锁定策略支持每个事务隔离级别,本质上事务是对锁和MVCC的封装。锁是实现数据库并发控制的基础。
在可重复读隔离级别下,默认对于有唯一索引的条件,使用记录锁。对于范围类型的索引,使用next-key,不仅锁定数据行,也会锁定索引间隙,来保证其他会话事务不会插入或删除数据到索引间隙中。这样就避免了幻读,不可重复读问题。
在读已提交隔离级别下,InnoDB
只锁定索引记录,而不是它们之前的间隙,因此允许在锁定记录旁自由插入新记录。间隙锁定仅用于外键约束检查和重复键检查。由于间隙锁定被禁用,可能会出现幻读问题,因为其他会话可以将新行插入间隙中。
提出几个问题?
通过几个小问题,加深对mysql锁事务的理解。
不手动开启事务,进行 insert update delete 会加锁吗?
隐性事务,默认会开启事务。
手动开启事务,执行多条语句,执行完一条语句,获取的锁会释放吗?
不会,直到事务提交持有的锁才会释放。
同一个事务下,锁是支持重入的吗?
锁重入的理解在java开发中,指持有锁的线程再次获取同一个锁。在mysql中,持有锁的事务,可以再次获取同一行或者其他行的共享锁或者互斥锁。
事务隔离级别和锁的关系?
数据库的事务隔离与锁机制有什么差别和联系?
加锁过程分析
Mysql 加锁过程详解(1)- 基础知识
InnoDB中不同SQL语句设置的锁 mysql5.7 官方文档
这俩篇强烈建议阅读
下篇,死锁演示1:排他锁的相互等待
听说点赞关注的人,身体健康,一夜暴富,升职加薪迎娶白富美!!!
点我领取每日福利
微信公众号:耿子blog
GitHub地址:gengzi
Mysql数据库死锁实战-锁的基础知识相关推荐
- mysql数据库死锁几种情况
mysql数据库死锁的产生原因及解决办法 数据库和操作系统一样,是一个多用户使用的共享资源.当多个用户并发地存取数据 时,在数据库中就会产生多个事务同时存取同一数据的情况.若对并发操作不加控制就可能会 ...
- MySQL数据库的简单使用(基础篇)
MySQL数据库的简单使用(基础篇) 学习说明 文章划分 三级模式的理解 安装及配置MySQL 登录MySQL(Windows下) 数据库操作 数据库引擎 MySQL执行外部的.sql文件 数据表的操 ...
- 金仓数据库 MySQL 至 KingbaseES 迁移最佳实践(3. MySQL 数据库移植实战)
3. MySQL 数据库移植实战 由于 KingbaseES 利用 KDTS-PLUS 等多种工具简化移植过程. 本节重点描述了在实际应用中移植一个 MySQL 数据库系统的完整过程,以及其中的主要移 ...
- MySQL数据库(表的CRUD基础操作(最常用))
作者:渴望力量的土狗 博客主页:渴望力量的土狗的博客主页 专栏:MySQL数据库 工欲善其事必先利其器,给大家介绍一款超牛的斩获大厂offer利器--牛客网 点击免费注册和我一起刷题吧 目录 理解CR ...
- 使用C语言调用mysql数据库编程实战以及技巧
今天编写使用C语言调用mysql数据库编程实战以及技巧,为其他IT同行作为参考,当然有错误可以留言,共同学习. 一.mysql数据库的C语言常用接口API 1.首先当然是链接数据库mysql_real ...
- mysql 死锁监视器_并发基础知识:死锁和对象监视器
mysql 死锁监视器 本文是我们名为Java Concurrency Essentials的学院课程的一部分. 在本课程中,您将深入探讨并发的魔力. 将向您介绍并发和并发代码的基础知识,并学习诸如原 ...
- mysql数据库帐户_MySQL数据库用户帐号管理基础知识详解
MySQL管理员应该知道怎样通过指定哪些用户可连接到服务器.从哪里进行连接,以及在连接 时做什么,来设置MySQL用户账号.MySQL3.22.11引入了两个更容易进行这项工作的语句:GRANT 语句 ...
- mysql数据库索引和锁和日志
数据库索引和锁 索引和锁在数据库中可以说是非常重要的知识点了,在面试中也会经常会被问到的. 本文力求简单讲清每个知识点,希望大家看完能有所收获 声明:如果没有说明具体的数据库和存储引擎,默认指的是My ...
- mysql数据库死锁的产生原因及解决办法
该文章为转载,如有侵权请及时联系 这篇文章主要介绍了mysql数据库锁的产生原因及解决办法,需要的朋友可以参考下 数据库和操作系统一样,是一个多用户使用的共享资源.当多个用户并发地存取数据 时,在数据 ...
- 记一次mysql数据库死锁实验
概述 之前接触到的数据库死锁,很多都是批量更新时加锁顺序不一致而导致的死锁,但是上周却遇到了一个很难理解的死锁.借着这个机会又重新学习了一下mysql的死锁知识以及常见的死锁场景.今天不介绍死锁的基本 ...
最新文章
- 代码审查规范(试用版)
- 谈一谈使用Python入门量化投资
- Java中的引用与C中的指针
- Android之使用AchartEngineActivity引擎绘制柱状图、曲线图
- 解决 from torch._C import *ImportError: DLL load failed: 找不到指定的程序。
- Scala入门到精通——第三节 Array、List
- ux的重要性_UX中清晰的重要性
- python测试4_Python 各种测试框架简介(四):pytest
- [Java基础]int和String的相互转换
- jquery查找ul属性不是hide,jQuery的ul显示/隐藏功能
- c++builder tadoquery存储过程_Electron桌面应用程序从创建项目、启动项目到打包程序的详细过程...
- [安全测试报告]针对某厂商的一次渗透性测试
- NUC1090 Goldbach's Conjecture【哥德巴赫猜想 】
- hadoop大数据平台_Hadoop之外的3个大数据平台
- 人人对战五子棋 C++
- 显示风场的某一局部区域,实现多分辨率
- 如何撤回 Gmail 已发送的邮件
- 计算机组成与原理第三章答,计算机组成与原理第三章答案.doc
- 三国志战略版:官渡之战_新阵容解读_曹操
- debian 11修改ip地址的方法
热门文章
- 通过Cubro解决方案轻松过渡到100Gbit
- ffmpeg教程 php推流,详解NODEJS基于FFMPEG视频推流测试
- win7打印机服务器修改ip,win7系统电脑更换IP地址后打印机不能打印文件了的解决方法...
- ATECLOUD智能云测试平台,中国人自己的“LABVIEW”-测试测量软件
- urllib实现请求发送(python3)
- Unity摄像机平滑处理跟随
- java 修改mac地址_XP下修改MAC地址
- Linux7网卡绑定后mac一样,如何解决双网卡bond0绑定模式物理成员口的mac地址和bonding接口mac地址不一致......
- Ubuntu 12.04更新源
- 医学方面的创业计划书_医学生创业计划书怎么写