原创文章,会不定时更新,转发请标明出处:http://www.cnblogs.com/janehoo/p/5603983.html

背景介绍:

innodb的锁分两类:lock和latch。
  其中latch主要是保证并发线程操作临界资源的正确性,要求时间非常短,所以没有死锁检测机制。latch包括mutex(互斥量)和rwlock(读写锁)。
  而lock是面向事务,操作(表、页、行)等对象,用来管理共享资源的并发访问,是有死锁检测机制的。
现在我们要着重讲的是innodb的lock锁,下面我们先来介绍几个概念。
  行锁:innodb实现了多粒度锁,作用对象为表则为表锁,作用对象为行(Record)则为行锁。其中行锁包括共享行锁和排他行锁。
  共享行锁(S):允许事务读取一行数据。
  排他行锁(X):允许事务删除或更新一行数据。
  意向锁:数据库需要对细粒度的对象上锁,需要首先给粗粒度的对象上锁。在粗粒度对象上上的锁成为意向锁。innodb的意向锁包括共享意向表锁和排他意向表锁。
  共享意向表锁(IS):S锁对应IS锁
  排他意向表锁(IX):X锁对应IS锁
  锁兼容:兼容是指在同一对象上允许同种或不同种锁同时存在。
lock锁的分类
  innodb实现了行级锁,包括行级共享锁(S)及行级排它锁(X),其中S和S是兼容的,其它都是不兼容的。所谓兼容是指对同一记录(row)锁的兼容性情况。innodb通过意向锁实现多粒度锁定。对innodb而言只有表意向共享锁(IS)和表意向排他锁(IX)。在给表加行锁前,需要先对该表加意向锁。因为意向锁是表级别的,而innodb的其它锁是行级别的,所以如果不是全表扫,意向锁是不会对堵塞其它请求的。(小编这里特地做了一个实验,发现select * from t1 where id=5 for update,此时id上面没有索引,走的是全表扫描,确实堵塞了其它任何请求。但给id加上索引,没有走全表时,就没有堵塞其它请求了。)各锁之间的兼容情况请看下图:

  

简记:含I的锁与含I的锁是相互兼容的
  含I的S锁与不含I的S锁兼容
  不含I的锁,含S的与含S的兼容与含X的不兼容
  不含I的锁,含X的与任何锁都不兼容

如何查看锁
1、通过show engine innodb status\G;
2、直接查询试图 innodb_trx,innodb_locks,innodb_lock_waits;
关于读请求的锁
读请求可以分为两类:一致性锁定读和一致性非锁定读。
  一致性锁定读是指读取数据的时候需要给表上加锁,有两种锁定形式:
  select * from t1 for update;(加的是X锁)
  select * from t1 in share mode;(加的是S锁)
  而一致性非锁定读是指读取数据的时候不给表加锁,利用MVCC(multi version concurrency control)特性当读取数据时如果碰到对象已经上了X锁就直接读取镜像数据。又因为事务隔离级别的不同,在不同事务隔离级别下读取的镜像也会不同。
锁的算法
锁有三种算法:
  Record Lock:单个记录上的锁
  Gap Lock:间隙锁(锁定范围但不包含记录本身)
  Next-Key Lock:锁定一个范围并且包括记录本身,Innodb对于行的查询都采用这种算法(为了解决幻读)。但查询的索引含有唯一属性(主键或唯一索引)时,innodb存储引擎会对next-key lock进行优化,将其降级为Record Lock。即仅锁住索引本身,而不是范围。若是辅助索引则会分别对当前辅助索引及聚集索引加锁定。对聚集索引采用Record Lock锁定,而辅助索引则使用Next-Key Lock锁定。需要注意的是如果是等值更新,innodb会对辅助索引值与前后值构成的范围加上gap lock,而如果该辅助索引值不存在,则在该值所在区间上加上gap锁。区间的划分和辅助索引包含的键值有关,如一个辅助索引包含了{1,3,5},则对应的区间有(-∞,1),(1,3),(3,5),(5,+∞)。例如更新值为2,则锁定(1,3)这两个区间,而如果更新值为3则锁住(1,3),[3],(3,5)这个范围。如果是范围查询的话,则锁定的是该SQL涉及的范围内的记录和间隙。确切地说,其实辅助索引的叶子节点都包含了对应的聚集索引值,在使用gap锁划分区间的时候,其实是根据[辅助索引,聚集索引]组成的二维数组来划分的。
阻塞:
给一个对象加锁会阻塞其它对象对它的请求,innodb通过设置innodb_lock_wait_timeout来控制等待时间,并通过设置innodb_rollback_on_timeout来设置是否等待超时对事务进行回滚,默认不回滚,超过等待时间则抛出异常,由用户判断是该rollback还是commit。
死锁:
死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种相互等待的现象。死锁出现的概率是非常低的。innodb内置有死锁检查机制。当出现死锁时会自动回滚占用undo资源少的事务。死锁的检测除了超时还有wait-for graph,如果图中出现环形回路则表明存在死锁。
锁升级:
很多数据库如:SQL server就有锁升级的想象,但是innodb并没有锁升级。这是因为innodb根据事务访问的每个页对锁进行管理,采用位图方式,因此不管一个事务锁住页中的一行还是多个记录,其开销通常都是一样的。
锁涉及的三类问题:
脏读:读到未提交的数据(Read-ncommitted隔离级别);
不可重复读:(Read-committed);
丢失更新:避免丢失更新的方式就是给select ... from ... 加上 for update;
锁的常见的误区
误区一:select col1,col2 from table1 where col1='xxx' 或select count(*) from table1;会锁表;
事实上这样的select语句是不会对访问的资源加锁的。因为这样的查询会使用一致性非锁定读,它访问的是资源的镜像(此处用到的技术是mvcc即multi version concurrency control),所以不会堵塞其它事务也不会被其它事务堵塞(感兴趣的同学可以通过实验验证,不清楚实验方法的话可以私信我)。当然这只是一般的select语句。如果是如下这种格式的语句仍然会对访问的资源加锁:
select col1,col2 from table1 for update;(加X锁)
select col1,col2 from table1 lock in share mode;(加S锁)
关于什么是共享锁(S)什么是互斥锁(X),上面已经做了介绍。我们需要注意的是S锁和S锁是兼容的,S锁和X锁、X锁和X锁是不兼容的。这里说的兼容指的是不同事务对同一行(row)资源的访问的兼容性。显式加锁的select请求,会堵塞其它资源对该表的意向锁请求,从而堵塞其它请求。所以一般情况下,如无特殊需求,是不允许应用对select语句显示加锁的。
误区二:update table1 set col1='xxx' where col2='xxx'不走索引对数据库的性能没有多大影响;
RR隔离级别下,当使用update语句时,首先该语句会对它所访问的表加意向排它锁(IX),如果update语句走了索引,那么它会使用行锁(X) ,只锁定访问的记录及间隙(想了解更多可以百度MySQL锁的算法)。而如果它没有走索引,就会进行全表扫,这时会给整个表上记录加上排他锁(X)。这句SQL就会堵塞所有其它会话对该表的加锁请求,从而堵塞其它请求。但如果数据库开启了innodb_locks_unsafe_for_binlog,会触发semi-consistent read对不满足条件的记录会释放它上面的排它锁,同时不加gap锁。
RC隔离级别下,SQL会走聚集索引的全扫描过滤,由于过滤是在MySQL server层进行的。因为每条记录无论是否满足条件,都会被加上X锁。但是出于效率考虑,mysql对于不满足条件的记录,会在判断后放锁,最终持有的,是满足条件的记录上的锁,但是不满足记录上的加锁/放锁动作不会省略(优化违背了2PL约束)。综上所述:使用当前读的SQL都必须要走索引
误区三:自增长键会在整个事务过程中,锁住自增长值;
现在我们数据库中的表的主键都是设为自增长的。很多同事认为,这样会不会非常影响数据库的插入效率。事实上使用自增长值确实会影响数据入库的效率,当时mysql 5.1.22版本后,对数据库的自增长设计做了很大的优化,性能已经得到了很大的提升。在5.1.22 之前的版本,使用的是auto_inc locking来生成自增长主键。它并不是在整个事务过程中锁住自增长资源而是在要生产主键的SQL执行完后就释放资源。这就是我们为什么会碰到,事务回滚后,自增长值确仍旧增大的原因。5.1.22及之后,使用了轻量级互斥量(mutex)来实现自增长,并通过inodb_atuoinc_lock_mode来控制自增长的模式。数据库默认该参数值为1,一般情况下都是用mutex来控制自增长,只有当bulk inserts的时候才会使用auto_inc locking模式。
误区四:使用外键加强约束,不会影响性能;
很多同事在设计表结构的时候喜欢使用外键,这里会给大家说明,为什么不建议大家使用外键。
如果使用外键,那么当子表需要更新或插入数据的时候会去检索父表。问题就出现在,检索父表的使用并不是使用的是一致性非锁定读,而是使用的一致性锁定读。
内部检索会是下面的格式:select * from parent where ... lock in share mode;这样的检索就会堵塞同时访问该父表的其它事务的请求,从而影响性能。

[小结]了解innodb锁的更多相关文章

  1. innodb 锁分裂继承与迁移

    innodb行锁简介 行锁类型 LOCK_S:共享锁 LOCK_X: 排他锁 GAP类型 LOCK_GAP:只锁间隙 LOCK_REC_NO_GAP:只锁记录 LOCK_ORDINARY: 锁记录和记 ...

  2. InnoDB锁机制分析

    InnoDB锁机制常常困扰大家,不同的条件下往往表现出不同的锁竞争,在实际工作中经常要分析各种锁超时.死锁的问题.本文通过不同条件下的实验,利用InnoDB系统给出的各种信息,分析了锁的工作机制.通过 ...

  3. MySQL数据恢复和复制对InnoDB锁机制的影响

    MySQL通过BINLOG记录执行成功的INSERT,UPDATE,DELETE等DML语句.并由此实现数据库的恢复(point-in-time)和复制(其原理与恢复类似,通过复制和执行二进制日志使一 ...

  4. [转载] 数据库分析手记 —— InnoDB锁机制分析

    作者:倪煜 InnoDB锁机制常常困扰大家,不同的条件下往往表现出不同的锁竞争,在实际工作中经常要分析各种锁超时.死锁的问题.本文通过不同条件下的实验,利用InnoDB系统给出的各种信息,分析了锁的工 ...

  5. mysql innodb锁简析(2)

    继续昨天的innodb锁的分析: 注:此博文参考一下地址,那里讲的也很详细.http://xm-king.iteye.com/blog/770721 mysql事务的隔离级别分为四种,隔离级别越高,数 ...

  6. MySQL · 特性分析 · innodb 锁分裂继承与迁移

    http://mysql.taobao.org/monthly/2016/06/01/ innodb行锁简介 行锁类型 LOCK_S:共享锁 LOCK_X: 排他锁 GAP类型 LOCK_GAP:只锁 ...

  7. Innodb 锁系列2 事务锁

    上一篇介绍了Innodb的同步机制锁:Innodb锁系列1 这一篇介绍一下Innodb的事务锁,只所以称为事务锁,是因为Innodb为实现事务的ACID特性,而添加的表锁或者行级锁. 这一部分分两篇来 ...

  8. Innodb 锁 (简单笔记)

    看过很多innodb锁的文章,已经明白的就不写了,简单做个笔记   Innodb 锁的兼容性: 1.意向锁和意向锁之间都是兼容的 2.X(排他锁)与任何锁都是不兼容的 3.排他意向锁 IX 于S锁是不 ...

  9. MySQL- InnoDB锁机制

    InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.行级锁与表级锁本来就有许多不同之处,另外,事务的引入也带来了一些新问题.下面我们先介绍一点背景知识 ...

随机推荐

  1. spring源码分析(一)

    一.首先分析AliasRegistry接口. 1.Alias别名,Registry注册表,AliasRegistry别名注册表接口. 2.共有四个方法,注册别名,判断是否别名,获取别名数组,移除别名. ...

  2. 微信小程序 循环列表添加点击事件和样式

    如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 <input/> 中的输入内容,<switch/> 的选中状态),需要使 ...

  3. ef linq 中判断实体中是否包含某集合

    我有一个需求,问题有很多标签,在查询时,需要筛选包含查询标签的一个集合(List<int>),以前的做法是先查询出来符合查询标签条件的标签id的结果集A,再查询问题时,加上判断是否包含该标 ...

  4. Oracle_PL/SQL(3) 游标

    引言:PLSQL数据类型标量数据类型:数字类.字符类.日期类.布尔类(boolean).复合数据类型:记录(%rowtype).表.数组引用类型:REF CURSORLOB类型:BLOB.CLOB 1 ...

  5. PAT 1045 快速排序(25)(STL-set+思路+测试点分析)

    1045 快速排序(25)(25 分) 著名的快速排序算法里有一个经典的划分过程:我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边. 给定划分 ...

  6. win10安装.net3.5

    近日有网友反映在windows10_64位系统电脑上安装Net framework3.5,操作时总失败,怎么办呢?小编下面就介绍win10 64位系统无法安装Net framework3.5的两种解决 ...

  7. mysql5.6改进子查询实测试

    表t1,t2 各自生成100万条记录. 表引擎  myiasm  ,查询语句 select * from t1 where id2 in (select id2 from t2 ) 查询速度 2.x秒 ...

  8. ubuntu增加工作分区命令

    参考自: https://www.cnblogs.com/wolflowhereu/p/5422653.html ubuntu增加工作分区(workspace)命令 dconf write  /org ...

  9. Shortest Unsorted Continuous Subarray LT581

    Given an integer array, you need to find one continuous subarray that if you only sort this subarray ...

  10. xcode如何运行下载的demo工程

    1. 首先你需要改Bundle Identifier,修改成别人没注册过的. 2. 选中 “Automatically manage signing” 3. 在Team里面添加自己的个人帐号了.