4.技术-mysql(四)-锁-何时加锁?加什么锁?

一.背景

    通过上节分析锁的基本概念,我们知道锁的模式有:

行级别的:(排他行锁)X、(共享行锁)S。

在加行锁之前需要先对库表页加意向锁:(意向排他锁)IX、(意向共享锁)IS。

以及实现锁的三种算法:

1>.record lock:锁住当前记录

2>.gap lock:锁住记录中间

3>.next-key lock:record lock+gap lock

这一节我们详细的分析这些锁的使用场景。

二.整体使用场景

1.普通的select操作(一致性非锁定读)不加任何锁(Serializable隔离级别加锁)。

2.UPDATE、DELETE和INSERT以及SELECT ... FOR UPDATE语句加IX和X锁。

3.SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE、

 唯一key Duplicate后当前事务会对该key加S锁。

create table new_table select * from old_talbe; 会对old_talbe加S锁

三.详细的分析加锁情况

注:不同的隔离级别解决的问题不同,比如读已提交解决脏读,重复读解决幻读,所以不同的隔离级别加锁机制不同(这点很重要,很多人上来看sql就说加什么锁,这种很不负责任)。

下图是一张整体的加锁这里只讨论Read Commited和Repeatable Read,其他两种基本不会用讨论意义不大。

分析加锁,首先要知道下面几点:(不同的条件加锁机制也不相同)

1>.隔离级别

2>.索引类型和执行计划

3>.更新的字段中是否有索引字段

先贴一下表结构

1>.场景一:Read Commited+无索引

设置隔离级别:set session transaction isolation level read uncommitted;

不走索引语句:update t_user set name ='mbj111' where text='text1'; 

图1:事务1模拟使用无索引字段更新未提交

图2:事务2模拟使用无索引字段更新

图3:确认下隔离级别:是Read Commited

图4:冲突锁展示,在主键索引加的X锁,id都是1。注:表字段解释见上篇。

结论:

Read Commited+无索引 对满足条件的记录对应的主键索引加X锁。

值得注意的是:此场景因为是全表扫描,实际处理过程较复杂如下:

1>.mysql server向innodb发起一笔当前读(一致性锁定读):select * from t_user where text='text1' 

2>.innodb收到该当前读请求发现全表扫描,会对所有主键索引的每一个节点加X锁并返回。

3>.mysql server收到结果集过滤,对不满足条件的记录解锁。

4>.mysql server对满足条件的记录发起更新的操作。

5>.innodb收到请求执行更新操作。

6>.mysql server发起commit命令给innodb

7>.innodb释放锁。

(更具体的流程后面的章节会详细的说)

从上面简易的流程可以看出,没有索引innodb对所有数据会执行加锁解锁的操作,这是由于MySQL的实现决定的如果一个条件无法通过索引快速过滤,那么存储引擎层面就会将所有记录加锁后返回,然后由MySQL Server层进行过滤。

在实际的实现中,MySQL有一些优化,在MySQL Server过滤条件,发现不满足后,会调用unlock_row方法,把不满足条件的记录放锁 (违背了2PL的约束,两阶段锁(Two-phase locking)约定加锁和解锁都在同一阶段执行,来保证加锁和解锁无交叉,在同一个事务中不会出现死锁)。这样做,保证了最后只会持有满足条件记录上的锁,但是每条记录的加锁操作还是不能省略的,并发下会影响性能。

2>.场景二:Read Commited+普通索引

普通索引语句:update t_user set name ='mbj123' where name='mbj111'; 

图1:数据展示

图2:执行计划展示

图3:RC隔离级别+模拟事务1根据普通索引更新未提交

图4:RC隔离级别+模拟事务2根据普通索引更新未提交

图5:冲突锁展示,可以看出对普通索引加了锁。

图6:事务2模式使用主键更新。

图7:冲突锁展示,可以看出对主键索引加了锁。

图8:模拟使用唯一索引更新(注意unique_no是字符型,值不带''不走索引)

图9:冲突锁展示,可以看出使用唯一索引更新依然对主键索引加了锁。

图10:模拟不使用索引。

图11:冲突锁展示,不使用索引意味着对主键加锁,引起主键锁冲突。

结论:RC+普通索引,会对所有满足条件的记录的普通索引加锁,并且会对对应的主键索引加锁。而对其他索引不加锁。

3>.场景三:Read Commited+唯一索引

图1:模拟使用唯一索引未提交

图2:模拟事务2使用唯一索引更新

图3:冲突锁展示,可以看出对唯一索引加锁

图4:事务2模拟主键更新

图5:冲突锁展示,可以看出引起主键锁冲突。

图6:事务2模拟使用非索引更新

图7:冲突锁展示:可以看出主键锁冲突了

图8:普通索引更新

图9:冲突锁展示:可以看出主键锁冲突了,因为普通所以会对主键加锁,而当前主键被事务1已经上锁。

结论:Read Commited+唯一索引:会对唯一索引和主键加锁,其他不加锁。

4>.场景四:Read Commited+主键索引

图1:事务1模拟主键事务未提交

图2:事务2模拟通过主键修改

图3:冲突锁展示:主键X锁冲突了

结论:Read Commited+主键索引,则对满足条件的主键索引加X锁。此场景性能最高。

5>.场景五:Repeatable Read+无索引

图1:事务1模拟无索引事务更新未提交

图2:事务2模拟无索引事务更新

图3:隔离级别展示,可以看出是可重复读

图4:锁展示,看出对主键加X锁了。

图5:事务2模拟更新其他行

图6:锁展示:等待id=1的主键X锁。

图7:事务2模拟执行插入

图8:锁展示:等待id=1的主键X锁。

结论:Repeatable Read+无索引,会对所有数据的主键加X锁,并且在记录的缝隙之间加GAP锁防止新记录插入来解决幻读。

也可以通过开启innodb_locks_unsafe_for_binlog来关闭GAP锁实现与RC隔离级别的处理方式。

mysql默认使用Repeatable Read隔离级别关闭innodb_locks_unsafe_for_binlog。

6>.场景六:Repeatable Read+普通索引

图0:看下目前的数据

 图1:事务1模拟根据普通索引修改未提交

图2:事务2根据普通索引修改同一行

图3:锁展示:锁定了普通索引。

图4:事务2根据id修改

图5:锁展示,锁定了主键

图6:事务2插入name=mbj14向(mbj12,mbj15]之间插入,被阻塞

图7:锁展示,可以看出等待锁模式为X+GAP。在普通索引上。

结论:对满足条件的记录加X锁+GAP锁,对应的主键加X锁。防止幻读。

注:上图的数据可以看出,普通索引mbj15上加X锁,在(mbj12,mbj15)和(mbj15,mbj18)加GAP锁,之间不会被插入数据。注意GAP锁是加在普通索引之间的不是唯一索引。

7>.场景七:Repeatable Read+唯一索引

图1:事务1根据唯一索引修改,未提交

图2:事务2根据唯一索引,修改同一行

图3:锁展示,对唯一索引加了X锁

图4:事务2根据其他字段修改,被阻塞

图5.锁展示,主键X锁。

图6.事务2插入name=mbj14向(mbj12,mbj15]之间插入,成功。

结论:Repeatable Read+唯一索引,同场景三,对满足条件的唯一索引和对应的主键索引+X锁。此时没有GAP锁,因为唯一性索引next key锁会降级为X锁。

8>.场景八:Repeatable Read+主键索引

图1:事务1模拟根据普通索引更新未提交

图2:更新其他行字段,发现更新成功,未阻塞。

图3:事务2模拟修改相同行,被阻塞

图4:锁冲突展示,id=15的主键索引加了X锁

图5:事务2模拟插入id=16的值,成功

结论:Repeatable Read+主键索引,同场景四,仅对主键加X锁。

场景九:update字段中含索引

图1:事务1模拟修改索引字段name,未提交。

图2:事务2根据name修改,对name索引上X锁。被阻塞

图3:锁展示,发现name索引冲突了。说明事务1正在占用。

结论:所有场景加锁的基础上,对索引字段修改会对该索引加锁。

场景十:S锁的使用场景之LOCK IN SHARE MODE

图1:事务1使用中

图2:select * from t_user LOCK IN SHARE MODE加S锁

图3:锁展示,可以看出加了S锁,与X锁冲突。

结论:S锁与X锁冲突。具体兼容性如下:

场景十一:S锁的使用场景之Duplicate entry for key 

图1:事务1发生Duplicate key

图2:事务2等待事务1

图3:锁冲突展示

结论:发生Duplicate key的事物会对该key持有S锁,直到回滚释放。此时对该索引加X锁是排斥的。

四.总结


    整理以上结论如下图,  后面章节会根据锁机制去编写适合高并发的SQL。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • MySQL 加锁处理分析 转载2013年12月13日 16:43:55 7598 原文地址:http://hede...
    初来的雨天阅读 445评论 0 2
  • 当一个系统访问量上来的时候,不只是数据库性能瓶颈问题了,数据库数据安全也会浮现,这时候合理使用数据库锁机制就显得异...
    初来的雨天阅读 3,560评论 0 22
  • 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式。同时数据库又是个高并...
    CodeKing2017阅读 610评论 0 7
  • 1背景1 1.1MVCC:Snapshot Read vs Current Read2 1.2Cluster In...
    简小鹿奔跑ing阅读 4,148评论 1 50
  • 背景 MySQL/InnoDB的加锁分析,一直是一个比较困难的话题。我在工作过程中,经常会有同事咨询这方面的问题。...
    MakeACoder阅读 610评论 0 3