什么是锁?

锁的相关概念

锁被设计出来的的初衷是为了处理并发访问,两个请求访问相同资源时候,为了防止发生冲突,创建一个锁文件,当下个请求到达时,如果锁文件存在,就排队等待锁所释放后进行访问,从而更加合理的控制资源的访问.

在 MySql 中锁大致分为3类,分别是,全局锁、表级锁和行锁。

全局锁

顾名思义,全局锁就是对整个数据库加锁,MySql 提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL),执行此命令后,整个库会处于一个只读状态,更新,删除,插入包括表结构的修改都会被阻塞,相反 unlock tables; 就是释放全局锁.

全局锁的主要应用场景主要是,做全库的逻辑备份

但是这样子会给业务带来极大的问题(业务停摆,从库的话无法同步binlog,造成主从延迟).

还有就是,在客户端断开连接后,全局锁会自动释放.

表级锁

表级锁主要有两种,表锁和 MDL(元数据锁) 两种. MDL 是自动加锁的,不需要显式启动.而表锁则需要手动启动.

表锁

表锁用于给某个单表加锁,锁的类型根据读写分为,读锁和写锁.在 MyIsam 时代,表级锁就是最小粒度的锁, 也是最常用的处理并发的方式;

表锁的语法是 lock tables tableName read/write,和全局锁一样,可以使用unlock tables;主动释放锁,或者客户端断开的时候会自动释放锁.

对于加锁的 A线程 来说,只能读 加了读锁的表, 能读写加了 写锁 的表,不能访问其他表.
对于其他 B线程来说, 不能写 加了读锁的表, 不能 读写 加了 写锁的表.可以访问其他表

例如:
线程 A 中执行 lock tables table1 read, table2 write; 这个语句,则其他线程写 table1、读写 table2 的语句都会被阻塞。同时,线程 A 在执行 unlock tables 之前,也只能执行读 t1、读写 t2 的操作,不能读写其他表。

在还没有出现更加细粒度的锁的时候,表锁是最常用的处理并发的方法,而对于 InnoDB 这种支持行锁的引擎,一般不使用 lock tables 命令来控制并发,毕竟锁住整个表的影响面还是太大。

MDL(metadata lock)元数据锁

MDL 是并发情况下维护数据一致性,在表上有事务时,不可以对元数据进行写入操作,并且这个操作是在 service 层实现的. 主要的作用时防止 DDL 和 DML 并发的冲突.
MDL 不需要显示使用,在访问一个表的时候会自动加上,MDL 的所用是,保证读写的正确性,你们想想一下如果查询正在遍历一个表的数据,,执行的时候,另一个线程对这个表的结构做了变更,删除了一列,那么查询线程拿到的结果和表结构对不上,肯定是不行的.

因此,在 MySQL 5.5 版本中引入了 MDL,当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁

  • 读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。
  • 读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。

所以当对线上数据库结构发生变化时,可能会锁住线上的查询和更新,那么应该如何安全的给小表加索引呢?

首先,我们要进行修改表之前,先看一下表上有没有长事务,事务如果不提交的话,会一直占用 MDL 锁,我们可以稍后执行 DDL ,或者先 kill 这个长事务;

如果这个表是个热点表,kill 可能不太管用了,我们可以在 alter 上设定一个等待时间,一段时间内拿不到 MDL 锁可以先放弃,不要阻塞后面的语句.

行锁

行锁是有引擎实现的,不是所有的引擎都支持行锁,不支持行锁意味着,要进行并发控制只能使用表锁,同一张表上,同时只能有一个更新在执行,这会严重影响到并发度,而 InnoDb 是支持行锁的,这是 MyISAM 被 InnoDB 代替的主要原因之一.

两阶段锁

事务A 事务B
begin;<br />update t set c = c+1 where id=1;<br />update t set c = c+1 where id=2;
begin;
update t set c = c+ 2 where id =1;
commit `

当事务A执行完两条sql, 而未提交时,它具有什么锁呢?锁什么时候释放呢?

我们可以试一下:

事务B 的语句会被阻塞,只有当事务A commit,事务B,才能继续执行.

知道了这个答案,不难猜出事务 A 持有的两个记录的行锁,都是在 commit 的时候才释放的。

也就是说,在 InnoDB 事务中,** 行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。**

所以,如果我们在事务中有多个语句,需要锁住多个行,要把最可能造成冲突,最能影响并发的锁尽量往后放

死锁和死锁检测

当你发现 CPU 消耗接近100%,但是数据库每秒执行了不到100 个事务,你叫要看一下是否出现死锁了;

发生死锁

如图,事务A 在等着事务B id =2 的行锁释放,而事务B 在等着事务A id=1的行锁释放,他们都在相互等着对方释放锁,就造成了死锁.

当死锁出现后,有两种方式

  • 直接进入等待,直到超时。
  • 发起死锁检测, 发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑。

超时时间可以通过 innodb_lock_wait_timeout 参数设置,默认 50s, 也就是说,按照第一种策略,第一个被锁住的线程要过 50s 才会超时退出,然后其他线程才有可能继续执行.

所以,正常情况下我们还是要采用第二种策略,即:主动死锁检测,而且 innodb_deadlock_detect 的默认值本身就是 on。主动死锁检测在发生死锁的时候,是能够快速发现并进行处理的,但是它也是有额外负担的。

每当一个事务被锁的时候,就要看看它所依赖的线程有没有被别人锁住,如此循环,最后判断是否出现了循环等待。假设有 1000 个并发线程要同时更新同一行,那么死锁检测操作就是 100 万次左右的。虽然最终检测的结果可能是没有死锁,但是这期间要消耗大量的 CPU 资源.这样就会导致 CPU 利用率很高,但却执行不了几个事务。

如果我们要解决这种热点行更新导致的性能问题呢?

  • 我们必须在业务层去保证一定不会出现死锁,然后临时把死锁检测关掉.
  • 控制并发度,比如同一行同时最多只有 10 个线程在更新,那么死锁检测的成本很会很高.
  • 把一行变为 "多行", 以影院余额为例,把影院的账户余额改为 10 个记录,影院的账户总额等于这 10 个记录的值的总和。这样每次要给影院账户加金额的时候,随机选其中一条记录来加。这样每次冲突概率变成原来的 1/10.
  • DML(data manipulation language):它们是SELECT、UPDATE、INSERT、DELETE,用来对数据库里的数据进行操作的语言
  • DDL(data definition language): DDL比DML要多,主要的命令有CREATE、ALTER、DROP等,DDL主要是用在定义或改变表(TABLE)的结构,数据类型,表之间的链接和约束等初始化工作上
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容