前两天听了姜老大关于InnoDB中锁的相关培训,刚好也在看这方面的知识,就顺便利用时间把这部分知识做个整理,方便自己理解。主要分为下面几个部分

1. InnoDB同步机制

InnoDB存储引擎有两种同步机制选择,一种是mutex,其是完全的互斥方法。另一种是rw-lock,可以给临界资源加上s-latch或者x-latch。其中s-latch允许并发的读取操作,而x-latch是完全的互斥操作。
mutex是基于test-and-set机制实现的,在其基础上做了优化。具体的流程为:
(1)线程调用test-and-set返回1,说明其他线程已经持有了这把锁,此时先进行自旋。自旋时间大约为20us
(2)再次获取mutex,如果还是不能获取到就放入wait array中,等待被唤醒。
2. Lock和Latch的区别
Lock
Latch
锁定对象
事务
线程
锁定持续时间
整个事务过程
临界资源持有过程
模式
行锁、表锁、意向锁
读写锁、互斥量
死锁
智能死锁检测
无死锁检测与处理机制
最重要的区别:Lock锁定时间从事物开始一直持续到事务结束,commit之后才会释放锁;而Latch就是通常意义上的锁,锁定临界资源,等其使用完之后就会释放锁。
3. 行锁/表锁/意向锁
(1)行锁和表锁比较简单,主要理解共享锁、排他锁以及两者的兼容关系。
(2)意向锁是实现多粒度锁的一种方式。InnoDB和Myisam不一样,可以同时支持行锁和表锁,对行锁的支持极大的提高了数据库的性能。那什么时候会用到表锁呢?
  • Flush tables with read lock;
  • select * from user where name = "libis" for update; 其中name字段不是user表的索引
这些情况下InnoDB都会上表锁。
那问题就来了,如果事务A正在修改user表的某条记录,事务B正好执行 select * from user where name = "libis" for update;事务B会得到执行吗?读者可以验证一下,事务B会被夯住,下图是事务B被夯住的情况,其中trx_id( 14376 )被14378阻塞:

为什么会这样?那可以这样想,如果事务B不会被事务A阻塞,会发生什么?假设事务B没有被事务A阻塞,事务B先执行了一次  select * from user where name = "libis" for update得到了一行记录,此时事务A正好了修改了这条记录,然后提交了,事务B再次执行上述select语句就肯定会得到不同的记录,这就违背了事务隔离性的要求。意向锁就是为了解决这样的问题。
事务A修改user表的记录r,会给记录r上一把X行锁,同时会给user表上一把意向排他锁(IX),这时事务B要给user表上表级排他锁就会被阻塞。意向锁通过这种方式实现了行锁和表锁共存且满足事务隔离性的要求。
4. 对可重复读和幻读的理解
(1)什么是不可重复读?什么是幻读?两者的区别是什么
不可重复读重点在同一个事务多次读同一条记录的时候,出现读到的数据不一致的情况。InnoDB通过MVCC的方式避免了不可重复读,即一致性的非锁定读。
幻读重点在同一个事务多次执行相同的SQL,可能返回之前不存在的行,或者之前存在的行之后不存在了。InnoDB使用Next-key Lock算法避免了幻读,即一致性的锁定读。
默认情况下,InnoDB使用一致性的非锁定读,即读取不会被阻塞。然而有些情况下用户希望通过锁定读取的方式保证数据的一致性,这时可以通过语法lock in share mode或for update主动对读取进行加锁操作,称这种方式为一致性的锁定读。
(2)InnoDB如何避免不可重复读?
见另一篇博文:InnoDB之MVCC机制与不可重复读
(3)InnoDB如何避免幻读?
在了解具体实现之前,首先对InnoDB中锁的算法有一定了解,InnoDB提供了三种锁算法:
  • Record Lock : 单个行记录上的锁
  • Gap Lock:锁定一个范围,但不包括记录本身
  • Next-Key Lock:锁定一个范围,包括记录本身
InnoDB就是使用Next-Key Lock算法避免幻读的,具体的实现方式可以举例如下:

有一张user表,只有一列uid,见下图:

里面有三条记录:

开启事务A,执行select * from user where uid > 4 for update,没有commit :
开启另一个事务B,执行insert into user values (5)
 
会发现这个事务会被夯住,执行下面查询数据库锁的语句可以看到,事务B被事务A阻塞住了,即事务B在等事务持有的锁:
 
再通过执行show engine innodb status查看具体的锁信息,可以看到事务A上了一把锁锁住了某个gap导致事务B等待: 
这会大家就应该知道Next-Key Lock的意义了吧,它锁住的是一个范围,而不是某一条记录,就拿上例来说,事务A锁住的是[4,6),[6,无穷大)这两个范围,因此向user中插入5是不可行的,直至事务A结束事务B才能执行成功,这样就可以避免幻读。
5. InnoDB中锁的实现机制
(1)页锁对象 + 位图 的实现方式
InnoDB中锁是根据页的组织形式进行管理的,行锁在InnoDB中的定义如下:
struct lock_rec_struct{
ulint space
ulint page_no
ulint n_bits
}
其中space/page_no可以唯一决定一个页,nbits是一个位图。因此要查看某行记录是否上锁,只需要根据space/page_no找到对应的页,然后根据位图中对应位置是否是1来决定此行记录是否上锁。
给某条记录上锁,首先查看记录所在页是否已经有锁对象,如果锁对象已经存在,则将位图上对应位置置1。如果不存在,则生成一个锁对象,然后将位图对应位置置1;
这种锁的实现机制可以最大程度地重用锁对象,节省系统资源,不存在锁升级的问题。可想而知,如果每个行锁都生成一个锁对象,将会导致严重的性能损耗,比如接近于全表扫描的查询就会生成大量的锁对象,内存开销将会很大。位图的方式很好地避免了这个问题。
(2)通过事务或(space,page_no)再Hash的方式组织页锁对象
InnoDB提供了两种方式对行锁进行访问:
通过事务中的trx_t变量访问。一个事务可能在不同页上有多个行锁,因此需要变量trx_locks将一个事务中的所有行锁信息进行链接,这样就可以很快地查看一个事务中的所有锁对象。
通过space/page_no访问。InnoDB提供了一个全局变量lock_sys_struct来方便查询行锁信息。lock_sys_struct包含一个HashTable,Hash的key是space/page_no,value是锁对象lock_rec_struct
6. InnoDB索引组织表的加锁过程
InnoDB是通过索引B+树进行组织的,因此对记录的加锁实际上是对索引的加锁。总的里说,加锁流程如下:
(1)通过主键进行加锁的语句,仅对聚焦索引记录进行加锁
(2)通过辅助索引进行加锁的语句,先对辅助索引进行加锁,再对聚焦索引记录进行加锁
(3)通过辅助索引进行加锁的语句,还可能需要对下一个辅助索引进行加锁(需要根据数据库的隔离级别而定)
详细的过程可以参考登博的博客: MySQL 加锁处理分析
7. 锁相关的运帷操作
(1)show engine innodb status;
(2)select r.trx_id waiting_trx_id , r.trx_mysql_thread_id waiting_thread, r.trx_query waiting_query , b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread , b.trx_query blocking_query from information_schema.innodb_lock_waits w inner join information_schema.innodb_trx b on b.trx_id = w.blocking_trx_id inner join information_schema.innodb_trx r on r.trx_id = w.requesting_trx_id;

相关阅读:InnoDB recovery过程解析

本文来自网易云社区,经作者范欣欣授权发布。

原文地址:InnoDB之锁机制

更多网易研发、产品、运营经验分享请访问网易云社区。

InnoDB之锁机制相关推荐

  1. Mysql InnoDB 的锁机制

    目录 前言 1. 锁的分类 1.1 实现方式 1.2 锁的粒度 2. 查询操作加锁方式 2.1 一致性非锁定读 2.2 一致性锁定读 3. 锁的算法 4. 锁的升级 5. 死锁 6.总结 前言 锁机制 ...

  2. mysql innodb 的锁机制_Mysql之Innodb锁机制详解

    InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.关于事务我们之前有专题介绍,这里就着重介绍下它的锁机制. 总的来说,InnoDB按照不同的分类共有 ...

  3. 从一个死锁看mysql innodb的锁机制

    2019独角兽企业重金招聘Python工程师标准>>> 背景及现象 线上生产环境在某些时候经常性的出现数据库操作死锁,导致业务人员无法进行操作.经过DBA的分析,是某一张表的inse ...

  4. 巧用MySQL InnoDB引擎锁机制解决死锁问题

    案例如下: 在使用Show innodb status检查引擎状态时,发现了死锁问题: *** (1) TRANSACTION: TRANSACTION 0 677833455, ACTIVE 0 s ...

  5. MySQL锁机制(myisam表所与innoDB锁)

    目录 1.MySQL锁的基本介绍 2.MyISAM表锁 2.1写锁阻塞读 2.2读阻塞写 3.InnoDB锁 3.1.事务及其ACID属性 3.2.并发事务带来的问题 3.3.1.在不通过索引条件查询 ...

  6. MySQL数据库:锁机制

    当数据库中多个事务并发存取同一数据的时候,若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性.MySQL锁机制的基本工作原理就是,事务在修改数据库之前,需要先获得相应的锁,获得锁的 ...

  7. MySQL调优(八):查缺补漏(mysql的锁机制,读写分离,执行计划详解,主从复制原理)

    mysql的锁机制 1.MySQL锁的基本介绍 ​ 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的 计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共 ...

  8. SQL优化之一则MySQL中的DELETE、UPDATE 子查询的锁机制失效案例

    关注"数据和云",精彩不容错过 前言 开发与维护人员避免不了与 in/exists.not in/not exists 子查询打交道,接触过的人可能知道 in/exists.not ...

  9. Mysql锁机制简单了解一下

    历史文章推荐: 可能是最漂亮的Spring事务管理详解 面试中关于Java虚拟机(jvm)的问题看这篇就够了 Java NIO 概览 关于分布式计算的一些概念 一 锁分类(按照锁的粒度分类) Mysq ...

  10. mysql的锁机制(读锁,写锁,表锁,行锁,悲观锁,乐观锁,间隙锁)

    读锁和写锁 介绍 MyISAM表锁中的读锁和写锁 读锁(共享锁S): 对同一个数据,多个读操作可以同时进行,互不干扰.加锁的会话只能对此表进行读操作,其他会话也只能进行读操作.MyISAM的读默认是加 ...

最新文章

  1. Tensorflow MNIST浅层神经网络的解释和答复
  2. MATLAB 表数据结构最终篇,如何实现表操作
  3. 解决通过 Visual Studio 打不开 ui 文件的问题
  4. go语言实现将word文件转成pdf_超实用的PDF在线转换器,你绝对用的到~
  5. android 9.0 一加6,一加6终于升级到安卓9.0,但这两个BUG令人遗憾!
  6. 程序员面试金典 - 面试题 05.01. 插入(位运算)
  7. 现如今有一个很有意思的现象,不管是工厂还是经销商
  8. linux与s7-300,Siemens SIMATIC S7-300硬编码凭证安全限制绕过漏洞
  9. Python环境搭建之OpenCV(转载)
  10. [转]十个让你变成糟糕的程序员的行为
  11. Spring之AOP面向切面编程
  12. python导入上级目录的模块
  13. 深入浅出统计学——笔记(一)1~3章
  14. gdiplus画直线
  15. 信号与系统(六)z变换
  16. 【协议】LLDP、ARP、STP、ICMP协议
  17. 各邮箱的邮件接收服务器和发送服务器
  18. 计算机课题推荐人意见,课题申请推荐人意见怎么写
  19. 空气净化器哪个牌子好,除甲醛空气净化器什么牌子好推荐
  20. Typora下载安装及使用方法

热门文章

  1. Atitit fsm有限状态机概念与最佳实践 目录 1. 概念组成与原理成分 1 1.1. 1、状态机的要素 4个要素,即现态、条件、动作、次态 2 1.2. 状态表 2 2. 性状 2 2.1.
  2. atitit 完整的知识体系表 学科体系表 v2
  3. Atitit (Sketch Filter)素描滤镜的实现  图像处理  attilax总结v2
  4. Atitit.异步编程技术原理与实践attilax总结
  5. Atitit.ui控件---下拉菜单选择控件的实现select html
  6. paip.应用程序远程WEB 接口的设计
  7. (转)券商IT研发现状:一年最多花5亿 中小公司靠外包
  8. 毕设题目:Matlab图像检索
  9. 2021中国研究生数学建模竞赛
  10. 【图像压缩】基于matlab GUI DCT图像压缩(压缩率可调)【含Matlab源码 1049期】