Mysql锁

mysql 锁机制

标签(空格分隔): mysql


参考文档

  1. https://www.2cto.com/database/201508/429967.html
  2. http://www.cnblogs.com/aipiaoborensheng/p/5767459.html

概念

  1. 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同的数据集的排他锁。
  2. 排他锁(X):允许获得排他锁的事务更新数据,但是组织其他事务获得相同数据集的共享锁和排他锁。
  3. 对于insert、update、delete,InnoDB会自动给涉及的数据加排他锁(X);对于一般的Select语句,InnoDB不会加任何锁,事务可以通过以下语句给显示加共享锁或排他锁。

共享锁

select * from table_name where .....lock in share mode

Note left of 事务1: select * from table_1 where id=1 lock in share mode;
事务1-->事务2: 
Note right of 事务2: select * from table_1 where id=1 lock in share mode;
事务2-->事务1: 
Note left of 事务1: update table_1 set age=10 where id=1;
Note left of 事务1: 事务1更新时发现此行锁被其他事务享用,等待
事务1-->事务2: 
Note right of 事务2: update table_1 set age=12 where id=1;
Note right of 事务2: 事务2更新时发现此行锁被其他事务享用,也等待,导致死锁

排他锁

select * from table_name where .....for update

Note left of 事务1: select * from table_1 where id=1 for update;
事务1-->事务2: 
Note right of 事务2: select * from table_1 where id=1 for update;
Note right of 事务2: 等待...
事务2-->事务1: 
Note left of 事务1: update table_1 set age=10 where id=1;
Note left of 事务1: 更新完后释放锁
事务1-->事务2: 
Note right of 事务2: 获得锁后,得到其他事务提交的记录

行锁的三种形式

  1. Record lock:锁定一条记录。
  2. Gap lock
  3. Next-key lock

innoDB锁问题

事务(Transaction)及其ACID属性

  • 原子性(Actomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
  • 一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以操持完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
  • 隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
  • 持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

并发事务带来的问题

  • 更新丢失(Lost Update):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题——最后的更新覆盖了其他事务所做的更新。例如,两个编辑人员制作了同一文档的电子副本。每个编辑人员独立地更改其副本,然后保存更改后的副本,这样就覆盖了原始文档。最后保存其更改保存其更改副本的编辑人员覆盖另一个编辑人员所做的修改。如果在一个编辑人员完成并提交事务之前,另一个编辑人员不能访问同一文件,则可避免此问题
  • 脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”的数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做“脏读”。
  • 不可重复读(Non-Repeatable Reads):一个事务在读取某些数据已经发生了改变、或某些记录已经被删除了!这种现象叫做“不可重复读”。
  • 幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。

事务隔离级别

| 隔离级别 | 脏读| 不可重复读 | 幻读 |
| -| - |
| 未提交读(Read uncommitted) | √ | √ | √ |
| 已提交度(Read committed) | x | √ | √ |
| 可重复读(Repeatable read) |x | x | √ |
| 可序列化(Serializable) | x | x | x |

mysql行锁的特性

  1. innodb 的行锁是在有索引的情况下,没有索引的表是锁定全表的.
    实例:
    id是主键
    | id| name|
    | -| - |
    | 1 | 1 |
    | 2 | 2 |
    | 3 | 3 |
    事务1update第一条id=1的数据,事务不提交;事务2接着update第二条id=2的数据的时候等待,原因是id没有加上索引,导致事务1锁的是表锁而不是行锁。

  2. 如果是使用相同的索引键,会出现锁冲突。
    示例:tab_with_index表中id字段有索引,name字段没有索引。
    事务1:

select * from tab_with_index where id = 1 and name = '1' for update;

事务2:

select * from tab_with_index where id = 1 and name = '4' for update;

虽然事务2访问的是和事务1不同的记录,但是因为使用了相同的索引,所以需要等待锁。

  1. 当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。
    示例:表tab_with_index的id字段有主键索引,name字段有普通索引。
    事务1:
select * from tab_with_index where id = 1 for update;

事务2:

select * from tab_with_index where name = '2' for update;

事务2使用name的索引访问记录,因为记录没有被索引,所以也可以获得锁。

间隙锁(Next-Key锁)

当 我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件 的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓 的间隙锁(Next-Key锁)。
示例:

Select * from  emp where empid > 100 for update;

是一个范围条件的检索,InnoDB不仅会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的“间隙”加锁。
InnoDB 使用间隙锁的目的,一方面是为了防止幻读,以满足相关隔离级别的要求,对于上面的例子,要是不使用间隙锁,如果其他事务插入了empid大于100的任何 记录,那么本事务如果再次执行上述语句,就会发生幻读.
还要特别说明的是,InnoDB除了通过范围条件加锁时使用间隙锁外,如果使用相等条件请求给一个不存在的记录加锁,InnoDB也会使用间隙锁!

一致性非锁定读

一致性非锁定读是指InnoDB存储引擎通过多版本并发控制技术来读取当前数据库的数据。如果当前读取的行正在执行delete或者update操作,这时读取操作不会等行锁的释放,而是去读取行的快照数据。


非锁定一致性读.png

快照数据是指改行之前版本的数据,该实现是通过undo段来实现的,而undo段用来在事务中保存回滚数据,因此使用快照没有增加额外的开销。
这是InnoDB存储引擎的默认读取方式。

注意

  1. 不同的事务隔离级别下读取的方式不同,并不是每个事务隔离级别下都是采用非锁定的一致性读。四种隔离级别中,READ COMMITTED和REPEATABLE READ这两种隔离级别使用非锁定的一致性读。
  2. 不同的事务即使都使用非锁定的一致性读,但是对于快照数据的定义也各不相同。READ COMMITTED级别下非锁定读总是读取锁定行的最新一份快照数据;而REPEATABLE READ级别下非锁定读总是读取事务开始时的数据版本。

例子

事务A 事务B
select * from table where id='1';
. update table set id =3 where id=1;
select * from table where id='1';
. commit;
select * from table where id='1';

上述例子中事务B update以后事务A第一次select的时候RC级别和RR级别获取的结果都是id=1的那一条数据;第二次select的时候,由于事务B已经提交,RC级别select的结果就是id=3,而RR级别读取的是事务开始时的数据,id=1。

一致性锁定读

默认配置下事务的隔离级别为REPEATABLE READ,select操作为非一致性锁定读,但某些情况下需要对数据库读取操作进行加锁保证数据的一致性。select 有两种一致的锁定读:

  • select ... for update
  • select ... lock in share mode

自增长与锁

InnoDB存储引擎内部对每个含有自增长列的表有一个自增长计数器,当进行insert操作时,首先获取计数器的最大值,加1后进行insert操作。这个操作会加一个特殊的表锁,AUTO-INC LOCK。这个锁并不是在事务提交后才释放,而是在insert语句执行完后释放。

缺点

虽然是insert后就释放锁,不是事务提交后才释放,但是必须等前一个insert的完成才能进行下一次insert,性能较差。

改进

TODO...

外键与锁

在对外键值进行update和insert操作时首先需要查询父表的记录,即select父表,这个select操作不是使用一致性非锁定读,因为会发生数据不一致的问题,为此需要使用一致性锁定读,这时使用的select ... lock in share mode方式。当父表对应记录加X锁后,子表的操作将会阻塞。

例子

TODO...

锁的算法

InnoDB存储引擎有三种行锁的算法

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

推荐阅读更多精彩内容

  • 当一个系统访问量上来的时候,不只是数据库性能瓶颈问题了,数据库数据安全也会浮现,这时候合理使用数据库锁机制就显得异...
    初来的雨天阅读 3,567评论 0 22
  • MySQL的事务支持 MySQL的事务支持不是绑定在MySQL服务器本身,而是与存储引擎相关: MyISAM:不支...
    但莫阅读 491评论 0 6
  • MySQL技术内幕:InnoDB存储引擎(第2版) 姜承尧 第1章 MySQL体系结构和存储引擎 >> 在上述例子...
    沉默剑士阅读 7,406评论 0 16
  • MyISAM 和 MEMORY 存储引擎采用的是表级锁;InnoDB 存储引擎即支持行级锁,也支持表级锁,但默认情...
    微日月阅读 893评论 0 0
  • 前言 数据库锁定机制是数据库为了保证数据的一致性而使各种共享资源在并发访问时变的有序的一种规则。MySQL数据库的...
    Justlearn阅读 1,663评论 0 4