前两天听了姜老大关于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引擎锁机制解决死锁问题(转)

    该文会通过一个实际例子中的死锁问题的解决过程,进一步解释innodb的行锁机制 最近,在项目开发过程中,碰到了数据库死锁问题,在解决问题的过程中,笔者对MySQL InnoDB引擎锁机制的理解逐步加深 ...

  2. InnoDB的锁机制浅析(五)—死锁场景(Insert死锁)

    可能的死锁场景 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/插入意 ...

  3. InnoDB的锁机制浅析(四)—不同SQL的加锁状况

    不同SQL的加锁状况 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/ ...

  4. InnoDB的锁机制浅析(三)—幻读

    文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/插入意向锁) Inno ...

  5. InnoDB的锁机制浅析(二)—探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/插入意向锁)

    Record锁/Gap锁/Next-key锁/插入意向锁 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Recor ...

  6. InnoDB的锁机制浅析(一)—基本概念/兼容矩阵

    InnoDB锁的基本概念 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Record锁/Gap锁/Next-key ...

  7. InnoDB的锁机制浅析(All in One)

    目录 InnoDB的锁机制浅析 1. 前言 2. 锁基本概念 2.1 共享锁和排它锁 2.2 意向锁-Intention Locks 2.3 锁的兼容性 3. InnoDB中的锁 3.1 准备工作 3 ...

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

    背景及现象 线上生产环境在某些时候经常性的出现数据库操作死锁,导致业务人员无法进行操作.经过DBA的分析,是某一张表的insert操 作和delete操作发生了死锁.简单介绍下数据库的情况(因为涉及到 ...

  9. Mysql中的锁机制

    原文:http://blog.csdn.net/soonfly/article/details/70238902 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的 计算资源(如 ...

随机推荐

  1. 合并区间 · Merge Intervals & 插入区间 · Insert Interval

    [抄题]: 给出若干闭合区间,合并所有重叠的部分. 给出的区间列表 => 合并后的区间列表: [ [ [1, 3], [1, 6], [2, 6], => [8, 10], [8, 10] ...

  2. [leetcode]340. Longest Substring with At Most K Distinct Characters至多包含K种字符的最长子串

    Given a string, find the length of the longest substring T that contains at most k distinct characte ...

  3. win10下安装oracle11G Examples出错[INS-32025][INS-52001]

    安装oracle examples时提示出错:[INS-32025] 所选安装与指定 Oracle 主目录中已安装的软件冲突.[INS-52001] Oracle Database Examples ...

  4. resin-pro-4.0.53报错java.lang.Error: java.lang.ClassNotFoundException: com.caucho.loader.SystemClassLoader

    最初并未发现,笔者的系统环境变量JAVA_HOME变量设置错误 D:\develop\Java\x64\jdk1.8.0_144 #最初使用了阉割版的JDK 改成完整安装的JDK就可以 D:\deve ...

  5. Django之virtualenv下安装xadmin

    1.安装xadmin,通过pip 进入virtualenv pip安装xadmin pyyuc:~ yuchao$ source PycharmProjects/mxvenv/bin/activate ...

  6. Gitlab不小心关闭了sign-in,无法登录web的坑。。。

    手贱一不小心用root在gitlab后台把登录功能给关了,当时我就懵逼了. 解决方法如下: #进入数据库修改配置[root@gitlab-server ~]# gitlab-psql gitlabhq ...

  7. JS如何获取PHP循环中的ID

    JS如何获取PHP循环中的ID  kaalrz 二路公交车    结帖率:83.33%   首先抱歉,因为昨天那帖图片几次都不能用,修改到不能再次修改,今天早上回帖又提示没有这个帖,只好重发一次. 如 ...

  8. 直压到亚马逊AWS平台,阿里云OSS平台或者腾讯云COS平台

    GTX Compressor (直压上云技术预览版) Powered by GTXLab of Genetalks. 技术预览版本下载地址: https://github.com/Genetalks/ ...

  9. URL编码转换函数:escape()、encodeURI()、encodeURIComponent()

          函数出现时间:                      escape()                                javascript 1.0           ...

  10. a标签的四个伪类

    A标签的css样式   CSS为一些特殊效果准备了特定的工具,我们称之为“伪类”.其中有几项是我们经常用到的,下面我们就详细介绍一下经常用于定义链接样式的四个伪类,它们分别是: :link    :v ...