mysql中的各种锁把我搞糊涂啦~
事务并发访问情况
读-读 情况
并发事务读取相同的数据,并不会对数据造成影响,允许并发读
写-写 情况
多事务并发写写时会发生脏写的情况,不过任何一个事务隔离级别都不允许此情况发生,通过加锁来杜绝脏写
脏写
事务T1 将数据改成了A,但是还未提交,可此时事务T2又将数据改成了B,覆盖了事务T1的更改,T1更新丢失,这种情况叫做脏写
加锁
例如,现在事务T1,T2对这条记录进行并发更改,刚才说是隔离级别是通过加锁来杜绝此脏写的,流程如下这个锁结构中有两个比较关键的信息(其实还有很多信息,后面再聊)
trx信息:表示这个锁结构是和哪个事务所关联的
is_waiting信息:表示当前事务是否正在等待
事务T1 将数据改成了A,但是还未提交,可此时事务T2又将数据改成了B,覆盖了事务T1的更改,T1更新丢失,这种情况叫做脏写
Q:能描述一下两个事务并发修改同一条数据时,mysql这个锁是怎么避免脏写的吗?
A :事务T1在更改这条数据前,就先内存中生成一把锁与此数据相关联(is_waiting为false,代表没有等待),然后咔咔一顿操作更改数据,这个时候,事务T2来了,发现此记录已经有一把锁与之相关联了(就是T1那一把锁),然后就开始等待(is_waiting为true代表正在等待),事务T1更改完数据提交事务后,就会把此事务对应的所结构释放掉,然后检测一下还有没有与此记录相关联的锁,结果发现T2还在苦苦的等待,就把T2的锁结构的(is_waiting为false,代表没有等待)然后把T2事务对应的线程唤醒,T2获取锁成功继续执行,总体流程如上。
读-写 /写-读 情况
在读-写 / 写 -读的情况下会出现脏读,不可重复读,幻读的现象,不同的隔离级别可以避免不同的问题,具体相关内容可以看小杰的这篇文章 京东面试官问我:“聊聊MySql事务,MVCC?”
不过贴心的我还是列出来了 注:√代表可能发生,×代表不可能发生
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read uncommitted RU) | √ | √ | √ |
读提交(read committed RC) | × | √ | √ |
可重复读(repeatable read RR) | × | × | √ |
串行化(serializable ) | × | × | × |
但是 RR在某些程度上避免了幻读的发生
怎么避免脏读、不可重复读、幻读这些现象呢?其实有两种方案
方案一 :读操作使用MVCC,写操作进行加锁
mvcc里面最重要的莫过于ReadView了,它的存在保证了事务不可以读取到未提交的事务所作的更改,避免了脏读。
在RC隔离级别下,每次select读操作都会生成ReadView
在RR隔离级别下,只有第一次select读操作才会生成ReadView,之后的select读操作都复用这一个ReadView
方案二:读写操作都用加锁
某些业务场景不允许读取旧记录的值,每次读取都要读取最新的值。例如银行取款事务中,先把余额读取出来,再对余额进行操作。当这个事务在读取余额时,不允许其他事务对此余额进行访问读取,直到取款事务结束后才可以访问余额。所以在读数据的时候也要加锁
锁分类
当使用读写都加锁这个方案来避免并发事务写-写、读-写、写-读时而产生的脏读,不可重复读,幻读现象时,那么这个锁它就要做到,读读时不相互影响,上面三种情况时要相互阻塞,这时锁也分了好几类,我们继续往下看
锁定读
共享锁(Shared Lock):简称S锁,在事务要读取一条记录时,需要先获取该记录的S锁
独占锁(Exclusive Lock):简称X锁,也称排他锁,在事务要改动一条记录时,需要先获取该记录的X锁
他们之间兼容关系如下 √代表可以兼容,×代表不可兼容
兼容性 | S锁 | X锁 |
---|---|---|
S锁 | √ | × |
X锁 | × | × |
事务T1获取某记录的S锁后,
事务T2也可以获取此记录的S锁,(兼容)
事务T2不可以获取此记录的X锁,直到T1提交后将S锁释放 (不兼容)
事务T1获取某记录的X锁后,
事务T2不可以获取此记录的S锁,直到T1提交后将X锁释放 (不兼容)
事务T2不可以获取此记录的X锁,直到T1提交后将X锁释放 (不兼容)
锁定读语句
SELECT .. LOCK IN SHARE MODE # 对读取的记录添加S锁SELECT .. FOR UPDATE # 对读取的记录添加X锁
多粒度锁
前面提到的锁都是针对记录的,其实一个事务也可以在表级进行加锁(S锁、X锁)
T1给表加了S锁,那么
T2可以继续获取此表的S锁
T2可以继续获取此表中的某些记录的S锁
T2不可以继续获取此表的X锁
T2不可以继续获取此表中的某些记录的X锁
T1给表加了X锁,那么
T2不可以继续获取此表的S锁
T2不可以继续获取此表中的某些记录的S锁
T2不可以继续获取此表的X锁
T2不可以继续获取此表中的某些记录的X锁
可是怎么可能平白无故的就给表加锁呢,难道没什么条件吗?答案是肯定有条件的
若想给表加S锁,得先确保表中记录没有X锁
若想给表加X锁,得先确保表中记录没有X锁和S锁
但是这个怎么确保呢?难道要一行一行的遍历表中的所有数据吗?当然不是啦,聪明的大佬们想出了下面这两把锁
意向共享锁(Intention Shared Lock):简称IS锁,当事务准备在某记录上加S锁时,需要先在表级别加上一个IS锁
意向独占锁(Intention Exclusive Lock):简称IX锁,当事务准备在某记录上加X锁时,需要先在表级别加上一个IX锁
让我们来看下加上这两把锁之后的效果是什么样子的
当想给记录加S锁时,先给表加一个IS锁,然后再给记录加S锁
当想给记录加X锁时,先给表加IX锁,然后再给记录加X锁
然后 经过上面的操作之后
如果想给表加S锁,先看下表加没加IX锁,如果有的话,则表明此表中的记录有X锁,则需要等到IX锁释放掉后才可以加S锁
如果想给表加X锁,先看下表加没加IS锁或者IX锁,如果有的话,则表明此表中的记录有S锁或者X锁,则需要等到IS锁或者IX锁释放掉后才可以加X锁
这几种锁的兼容性如下表
兼容性 | IS锁(表级锁) | S锁 | IX锁(表级锁) | X锁 |
---|---|---|---|---|
IS锁(表级锁) | √ | √ | √ | × |
S锁 | √ | √ | × | × |
IX锁(表级锁) | √ | × | √ | × |
X锁 | × | × | × | × |
IS、IX锁都是表级锁,他们可以共存。
他们的提出仅仅是为了在之后加表级别的S锁或者X锁时可以快速判断表中的记录是否被上锁,避免用遍历的方式来查看一行一行的去查看而已
InnoDB中的行级锁
Record Lock(记录锁)
官方名字 LOCK_REC_NOT_GAP
仅仅锁住一条记录
有S型和X型之分
Gap Lock(间隙锁)
官方名字 LOCK_GAP
给某记录加此锁后,阻塞数据在此记录和上一个记录的间隙插入,但是不锁定此记录
有S型和X型之分,可是并没有什么区别他们的作用是相同的,gap锁的作用仅仅是为了防止插入幻影记录而已,如果对一条记录加了gap锁(无论S/X型)并不会限制其他事务对这条记录加Record Lock或者Gap Lock
Next-Key Lock(记录锁+间隙锁)
官方名字 LOCK_ORDINARY
既可以锁住某条记录,又可以组织其他事务在该记录面前插入新记录
Insert Intention Lock(插入意向锁锁)
官方名字 LOCK_INSERT_INTENTION
事务在插入记录时,如果插入的地方加了gap锁,那么此事务需要等待,此时此事务在等待时也需要生成一个锁结构,就是插入意向锁
锁内存结构
我们难道锁一条记录就要生成一个锁结构吗?
当然不是!
一个锁结构
如果被加锁的记录符合下面四条状态的话,那么这些记录的锁则会合到一个锁结构中
在同一个事务中进行加锁操作
被加锁的记录在同一个页面中
加锁的类型是一样的
等待的状态是一样的
锁结构信息
然后我们再来依此看下这个所结构每个部分的信息都是什么意思
锁所在的事务信息:无论是表级锁还是行级锁,一个锁属于一个事务,这里记载着该锁对应的信息
索引信息:对于行级锁来说,需要记录一下加锁的记录属于哪个索引
表锁/行锁信息:行级锁
Space_ID:记录所在的表空间 *** Page Number**:记录所在的页号
n_bits:一条记录对应着一个比特;一个页面包含多条记录,用不同的比特来区分到底是那一条记录加了锁,有个计算公式如下(公式中是取商)
n_bits = (1+(n_recs+LOCK_PAGE_BITMAP_MARGIN)/ 8)x 8
LOCK_PAGE_BITMAP_MARGIN是固定的值为64,n_recs指当前界面一共有多少条记录(包含伪记录以及在垃圾链表中的记录),
type_mode:32比特的数
lock_mode(锁模式):低4比特位表示
LOCK_AUTO_INC(十进制的4):表示AUTO-INC锁
LOCK_IS(十进制的0):表示共享意向锁,IS锁
LOCK_IX(十进制的1):表示独占意向锁,IX锁
LOCK_S(十进制的2):表示共享锁,也就是S锁
LOCK_X(十进制的3):表示独占锁,也就是X锁
lock_type(锁类型):第5~8比特位表示
LOCK_TABLE(十进制的1):当第5比特位设置为1时,表示表级锁
LOCK_REC(十进制的32):当第6比特位设置为1时,表示行级锁
rec_lock_type(行锁的具体类型):其余的比特位表示
第9比特设置为1时,表示is_waiting为true,即当前事务获取锁失败,处于等待状态
第9比特设置为0时,表示is_waiting为false,即当前事务获取锁成功
LOCK_ORDINARY(十进制的0):表示next-key锁
LOCK_GAP(十进制的512):当第10比特位是1时,表示gap锁
LOCK_REC_NOT_GAP(十进制的1024):也就是当第11比特设置为1时,表示Record Lock(记录锁)
LOCK_INSERT_INTENTION(十进制的2048):也就是当第12比特设置为1时,表示Insert Intention Lock(插入意向锁)
LOCK_WAIT(十进制的256):也就是当
其他信息:此文章不讨论
一堆比特位:此文章不讨论
举个例子
事务T1 要给user表中的记录加锁,假设这些记录存储在表空间号为20,页号为21的页面上,T1给id=1的记录加S型Record Lock锁,假如当前页面一共有5条记录(3条用户记录和2条伪记录)
过程:先给表加IS锁,不过我们现在不关心,只关心行级锁, 具体生成的所结构如下图所示
特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:长按订阅更多精彩▼如有收获,点个在看,诚挚感谢
mysql中的各种锁把我搞糊涂啦~相关推荐
- mysql rr gap nextkey_mysql中的各种锁把我搞糊涂啦~
事务并发访问情况 读-读 情况 并发事务读取相同的数据,并不会对数据造成影响,允许并发读 写-写 情况 多事务并发写写时会发生 脏写的情况,不过任何一个事务隔离级别都不允许此情况发生,通过 加锁来杜绝 ...
- 复习Java小球游戏代码分享Java面试题MySQL中常用的锁生活【记录一个咸鱼大学生三个月的奋进生活】021
记录一个咸鱼大学生三个月的奋进生活021 复习Java小球游戏 游戏界面的代码 小球运动线程的代码 运行游戏的代码 运行结果 代码分享 学习Java面试题(MySQL中常用的锁) 照片分享 复习Jav ...
- 把MySQL中的各种锁及其原理都画出来
疫情期间在家工作时,同事使用了 insert into on duplicate key update 语句进行插入去重,但是在测试过程中发生了死锁现象: ERROR 1213 (40001): De ...
- 一文带你了解 MySQL 中的各种锁机制!
MySQL中的锁机制,按粒度分为行级锁,页级锁,表级锁,其中按用法还分为共享锁和排他锁. 行级锁 行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁. 行级锁能大大减少数据库操作 ...
- mysql 获取距离当前最新的记录_一文带你了解 MySQL 中的各种锁机制!
云栖号资讯:[点击查看更多行业资讯] 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! MySQL中的锁机制,按粒度分为行级锁,页级锁,表级锁,其中按用法还分为共享锁和排他锁. 行级锁 ...
- 一文带你了解MySQL中的各种锁机制!
云栖号资讯:[点击查看更多行业资讯] 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! MySQL中的锁机制,按粒度分为行级锁,页级锁,表级锁,其中按用法还分为共享锁和排他锁. 行级锁 ...
- 悲观锁和乐观锁_带你了解MySQL中的乐观锁与悲观锁
在并发控制编程中锁是一个非常重要的概念,锁对于数据和业务一致性的保证起到关键作用,锁可以是程序层面的,也可以是数据库层面的,今天本文就通过MySQL来说明悲观锁与乐观锁两种常见的锁机制. 悲观锁 悲观 ...
- 【MySQL】MySQL中的表锁
锁是计算机协调多个线程并发访问某一资源的机制. 在数据库中,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个 ...
- MySQL中的各种锁(行锁、间隙锁、临键锁等等LBCC)
目录 1.快照读和锁定读 1.1 一致性读 / 快照读 1.2 锁定读 1.2.1 共享锁和独占锁 1.2.2 锁定读的语句 1.2.2.1 Lock In Share Mode 对记录加S共享锁 1 ...
最新文章
- 你的模型刚不刚?谷歌提出“刚度”概念,探索神经网络泛化新视角
- 美国半导体十年计划中的NO.1,模拟硬件究竟有什么价值?
- 几款表贴LED反向电流特性
- 2010年第一届蓝桥杯省赛 —— 第二题
- [BZOJ1444]有趣的游戏(AC自动机+矩阵乘法)
- oracle =1,oracle中的 where 1=1 和where 1 !=1
- cisco设备vlan,trunk,以太网通道管理
- python中的数据成员有两类_Python类和对象
- FFmpeg入门详解之52:ffplay源码分析
- Python 流体动力学层流建模
- 【Python精彩案例】生成动态二维码
- 老话题,火车票抢票助手,简化版 (漏洞已经失效^_^)
- 手动删除oracle数据库
- 腾讯云 直播 OBS 在线推流
- intellij idea weblogic 下面 怎么远程断点
- 英语口语测试对话软件,英语口语人机对话软件
- 振江我的老朋友,又来了,杭萧也没让我失望呀
- 修改Win7开机登录界面背景图片
- 关于右模糊匹配的优化
- 基于php+MySQL的网络在线考试系统
热门文章
- XML – E4X概述
- Linux中rsync备份数据使用实例
- 在Linux中如何禁止用户登录
- poj3352(强连通分量)
- PTA团体程序设计天梯赛-L2-010 排座位
- P4216 [SCOI2015]情报传递 LCA+树上主席树 离线操作
- Codeforces Round #640 (Div. 4)(ABCDEG题解)
- Codeforces数学1600day3[数学CodeForces - 1213D2, CodeForces - 1165E 数论,CodeForces - 1165D 因子分解]
- Educational Codeforces Round 84 (Rated for Div. 2) A~ ESZU cf集训
- 红书《题目与解读》第一章 数学 题解《ACM国际大学生程序设计竞赛题目与解读》