MySQL技术内幕-InnoDB存储引擎(第6章)

第6章 锁

什么是锁

Lock与Latch

latch一般称为轻量级锁,因为其要求锁定的时间必须非常短。用来宝成并发线程操作临界资源的正确性,并且通常没有死锁检测机制,在InnoDB中又可分为:

  • mutex(互斥量)
  • rwlock(读写锁)

lock的对象是事务,用来锁定数据库中的对象:表、页、行。有死锁机制。下面主要讲的是lock

InnoDB存储引擎中的锁

锁的类型

两种标准的 级锁:

  • 共享锁(S Lock),允许事务读一行数据
  • 排他锁(X Lock),允许事务删除或更新一行数据。

锁兼容:多个事务可以获得同一个行的共享锁。其他情况锁都不兼容

意向锁(表级别的锁),设计目的是在一个事务中揭示下一行将被请求的锁类型,支持两种:

  • 意向共享锁(IS Lock),事务想要获得一张表中某几行的共享锁
  • 意向排他锁(IX Lock),事务想要获得一张表中某几行的排他锁

由于InnoDB存储引擎支持的是行级别的锁,因此意向锁其实不会阻塞除全表扫描以外的任何请求。

介绍InnoDB提供的数据使用方法,可以对当前事务运行与获取锁的情况进行分析。

一致性非锁定读

快照读,读取该行之前版本的数据,通过undo段来完成。
一个行记录可能有不止一个快照数据,一般称这种技术为:行多版本技术。由此带来的并发控制,称之为多版本并发控制(Multi Version Concurrency Control, MVCC)。

一致性非锁定读(快照读)在第2和第3个隔离级别下使用,但读取的版本不同:

  • 第2隔离级别 READ COMMITTED,读取最新的快照(当前时刻的)
  • 第3隔离界别 REPEATABLE READ,总是读取事务开始时的行数据版本(从开始时间算起,最旧的数据)

一致性锁定读

InnoDB存储引擎对SELECT语句支持两种一致性的锁定读(locking read)操作:

  • SELECT ... FOR UPDATE (加X锁)
  • SELECT ... LOCK IN SHARE MODE (加S锁)

上面两个操作必须在事务当中

自增长与锁

自增长语句有四种类型:

  • insert-like(所有插入语句)
  • simple inserts(最简单的,插入前可以确定值)
  • bulk inserts(插入前不能确定值)
  • mixed-mode inserts (2和3的混合)

自增长锁的模式:

  • 通过表锁AUTO-INC Locking(过时了)
  • 对于simple inserts采用互斥量(mutex),对于bulk inserts采用AUTO-INC Locking。当前默认,并且基于语句的主从复制可以正常工作
  • 对于所有insert-like语句都通过互斥量,性能最高。但只能采用基于行的主从复制。

对于上述中主从复制的影响,考虑是因为内存中对互斥量的获取顺序是不能确定的,最终的id值也就没法确定,所以只能基于行来复制。

外键和锁

对于外键值得插入或更新,首先要查询父表中的记录,只能采用一致性锁定读,加S锁,来保证与父表的数据一致性。

锁的算法

行锁的3中算法

InnoDB存储引擎有3中行锁的算法:

  • Record Lock:单个行记录上的锁
  • Gap Lock:间隙锁,锁定一个范围,但不包括记录本身
  • Next-Key Lock:Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身

采用Next-Key Lock的锁定技术称为Next-Key Locking。设计的目的是为了解决Phantom Problem(幻读)。称作Next-Key的原因是锁定的区间类似(],左开右闭。对应的也有Previous-Key Locking(左闭右开)。

当查询的索引含有唯一属性时(仅单列唯一索引的情况,多列的话仍是范围),Next-Key Lock可以优化降级为Record Lock,仅锁住索引本身。

从文中的例子可以看到,Gap Lock的作用阻止多个事务将记录插入到同一个范围内,而这会导致Phantom Problem问题。

解决Phantom Problem

Phantom Problem是指在同一事务下,连续执行两次同样的SQL语句可能导致不同的结果,第二次的SQL语句可能返回之前不存在的行。
InnoDB存储引擎采用Next-Key Locking来避免Phantom Problem,但必须显式的加锁,否则使用快读,不会加Next-Key Lock,例如:
SELECT * FROM t WHERE a>2 <u>FOR UPDATE</u>

用户可以通过InnoDB存储引擎的Next-Key Locking机制在应用层面实现唯一性检测 这里没看明白

锁问题

锁提高了并发,却会带来问题。但因为事务隔离性的要求,锁只会带来三种问题。

脏读

在事务隔离级别为READ UNCOMMITTED时,当前事务读取到其他事务未提交的修改。

不可重复读

在一个事务内读取同一数据集合,在这个事务还没结束时,另外一个事务也访问了该同一个数据集合,并做了DML(Data Manipulatin Language,数据库操纵语言)操作。由于第二个数据的修改,导致第一个事务两次读取到的数据可能是不一样的,这种情况称为不可重复读。
与脏读相比,不可重复读是读取了其他事务已提交的数据
与幻读相比,从书中P270和P274的描述中,指不可重复读和Phantom Problem是相同的问题。

丢失更新

一个事务的更新操作被另一个事务的更新操作所覆盖,从而导致数据的不一致。但目前数据库不存在这个问题。本节主要描述应用系统中的更新丢失。

为了避免应用系统中更新丢失的问题,应该在事务开始时就对SELECT的数据加排他锁,例如:
SELECT * FROM account WHERE user=pUser <u>FOR UPDATE</u>

阻塞

由于不同锁之间的兼容性关系,在有些时刻一个事务中的锁需要等待另一个事务中的锁释放它所占用的资源,这就是阻塞。
阻塞时间超时,默认配置InnoDB不会进行回滚(大部分异常,死锁除外)。因此用户必须判断是是否需要COMMIT还是ROLLBASCK

死锁

死锁是指两个或两个以上的事务在执行过程中,因争夺资源而造成的一种相互等待的现象。

InnoDB采用wait-for graph(等待图)的方式来主动检查死锁,wait-for graph要求数据库保存以下两种信息:

  • 锁的信息链表
  • 事务等待链表
    通过链表构造出一张图,入股图中存在环,就代表存在死锁。当发现死锁InnoDB存储引擎选择回滚undo量最小的事务。

使用深度优先算法检测是否有环,InnoDB1.2版本之前采用递归实现,1.2版开始采用非递归实现。

判断有向图存在环:
方法一:遍历删除入度为0的节点,如果还有剩余节点,则说明有环(用循环O(n^2),用栈O(n+e))
方法二:DFS
判断有向图是否有环
Detect Cycle in a Directed Graph

死锁概率

发生概率和以下三点因素有关:

  • 事务的数量,数量越多概率越大
  • 每个事务操作的数量,操作的数量越多,发生死锁的概率越大
  • 操作数据的集合,越发生死锁的概率越。这里操作数据集合应该指的是数据总量

死锁的示例

这里介绍了另一个中死锁,和AB-BA死锁不同,死锁发生时处理方式也不同,这种情况会滚undo log记录大的事务

锁升级

锁升级(Lock Escalation)是指将当前锁的粒度降低:
行锁->页锁->表锁
InnoDB存储引擎不存在锁升级的问题。因为其不是根据每个记录来产生行锁的,相反,其根据每个事务访问的每个页对锁进行管理的,采用位图的方式。因此不管一个事务锁住页中一个记录还是多个记录,其开销通常都是一致的。

第七章 事务

认识事务

概述

ACID

分类

从事务理论的角度来说,可以把事务分为以下几种类型:

  • 扁平化事务:普通事务,要么全部提交,要么全部回滚
  • 带有保存点的扁平事务:在普通事务的基础上,可以回滚到指定的保存点,然后重新执行事务
  • 链事务:将事务按照保存点分成一个一个事务,链成一个链
  • 嵌套事务:层次结构框架,由一个顶层事务控制着各个层次的事务。树状结构
  • 分布式事务:分布式系统环境下的事务问题。需要分布式锁等来解决。

事务的实现

隔离性:由锁来实现
原子性和持久性:redo log(重做日志)
一致性:undo log

redo:恢复提交事务修改的页操作,通常是物理日志,记录的是页的物理修改操作。基本上都是顺序写

undo:回滚行记录到某个特定版本,是逻辑日志,根据每行记录进行记录。需要进行随机读写

redo

基本概念

redo由两部分组成:

  • 内存中的重做日志缓冲(redo log buffer),是易失的
  • 重做日志文件(redo log file),是持久的

log block(日志块)

在InnoDB引擎中,重做日志缓存、重做日志文件都是以512字节进行存储的,称之为重做日志块(redo log block)。

log group(重做日志组)

InnoDB存储引擎实际上只有一个log group。

redo log 重做日志格式

到InnoDB1.2版本时,一共有51种重做日志类型。

LSN(Log Sequence Number)

表示日志序列号,在InnoDB存储引擎中,LSN占用8字节,并且单调递增。LSN表示的含义有:

  • 重做让日志写入的总量,单位为字节
  • checkpoint的位置
  • 页的版本

恢复

不管上次数据库运行时是否正常关闭,都会尝试进行恢复。由于重做日志时物理日志,因此其是幂等的。

undo

基本概念

redo存放在重做日志文件中。
undo存放在数据库内部的一个特殊段(segment)中,这个段称为undo段(undo segment)。undo段位于共享表空间内。
unodo是逻辑日志:当用户执行ROLLBACK时,对于事务中每个INSERT,InnoDB存储引擎会完成一个DELETE;对于每个DELETE,InnoDB存储引擎会执行一个INSERT;对于每个UPDATE,InnoDB存储引擎会执行一个相反的UPDATE,将修改前的行放回去。

MVCC:
出了回滚操作,undo的另一个作用是MVCC,即在InnoDB存储引擎中MVCC的实现是通过undo来完成的。当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可以通过undo读取之前行版本信息,以此实现非锁定读取。

undo log会产生redo log,也就是undo log的产生会伴随着redo log的产生,这时因为undo log也需要持久性的保护。

undo 存储管理

当事务提交时,InnoDB存储引擎会做两件事:

  • 将undo log放入列表中,以供之后的purge操作
  • 判断undo log所在的页是否可以重用,若可以则分配给下个事务使用
    因为多版本中undo log依赖的问题,undo log最终的删除由purge线程来完成,并不是在事务提交后立即删除(insert undo log 可以立即删除)。

undo log格式

在InnoDB存储引擎中,undo log分为两种:

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

推荐阅读更多精彩内容