innodb中的锁分为S锁,即共享锁,另外一种为X锁,排它锁,好比:html
共享锁(S)mysql
select * from supplier where id=5 lock in share mode;
复制代码
排他锁(X)sql
select * from supplier where id=5 for update;
复制代码
或者insert,delete,update语句,这都是排他锁spa
兼容性3d
这两种锁的兼容以下:日志
X | S | |
---|---|---|
X | N | N |
S | N | Y |
意向锁code
能够理解为属于S锁和X锁的父节点,即要获取S锁或者X锁的话,必须先提早获取意向锁,即IS或者IX锁,那综合起来看下,这两类锁的兼容状况以下cdn
X | S | IX | IS | |
---|---|---|---|---|
X | N | N | N | N |
S | N | Y | N | Y |
IX | N | N | Y | Y |
IS | N | Y | Y | Y |
隐式锁htm
也是醉了,为何要搞这么多概念。。这种锁,能够认为不冲突的时候不加锁,这个时候的锁就是隐式锁,等遇到冲突了,该锁会升级为显示锁,仍是经过一个例子来讲明吧:blog
select * from test01 where age=21 for update;
复制代码
咱们看到mysql中实际上是没有找到锁的:
事务2
insert into test01(id,name,age) values(8,'zzh',22);
复制代码
这个时候因为[21,23)有gap锁,因此事务2会被阻塞住,这个时候再看mysql中的锁记录
具体在事务的不一样隔离级别下,不一样的场景加锁分析,在hedecheng加锁分析这篇文章已经讲解的很是详细了,这里就再也不多说了。主要说下其余状况下总结的一些加锁分析。
先来看官网对该锁的解释
insert into test01(id,name,age)values(12,"zzh",33);
复制代码
事务2
insert into test01(id,name,age)values(12,"zzh",33);
复制代码
事务3
insert into test01(id,name,age)values(12,"zzh",33);
复制代码
以下图操做:
事务1
rollback
复制代码
因此存在 事务2->事务3,事务3->事务2 死锁发生
官网中还要另外一个相似的例子,这里就很少作分析了,缘由相似。
下面咱们看下另外一种状况:
select * from test01 where age=21 for update;
复制代码
事务2(事务id=2945)
insert into test01(id,name,age)values(2,"zzh",22);
复制代码
事务3(事务id=2946)
select * from test01 where age=21 lock in share mode;
复制代码
执行以下
而后咱们提交事务1 事务1
commit;
复制代码
咱们再从新执行事务1
事务1(事务id=29467)
select * from test01 where age=21 for update;
复制代码
执行结果被阻塞:
该语句加锁分为两种状况
select * from test01 where age=21 for update;
复制代码
事务2
insert into test01(id,name,age)values(3,"zzh",22);
复制代码
事务1
insert into test01(id,name,age)values(3,"zzh",100);
复制代码
按如上顺序执行结果:
select * from test01 where age=21 for update;
复制代码
事务2(事务id=29683)
select * from test01 where age=21 for update;
复制代码
事务1
insert into test01(id,name,age)values(3,"zzh",22);
复制代码
执行结果以下
事务2
insert into test01(id,name,age)values(3,"zzh",22);
复制代码
由上面的分析一样得出事务2的等待有两种状况:
(1) 和事务1同样,等待age=22的插入意向锁,此时发现已经有事务1在等待该位置的插入意向锁,那就等待该位置的S锁
(2) 事务1虽然在age=22的插入意向锁等待,可是id=3的插入意向锁是加成功了,因此若是事务2在id=3这里等待插入意向锁的话,也会有冲突,那就等待该位置的S锁
因此,有这两种状况都会致使事务出现死锁,咱们具体看下死锁日志:
咱们上面有分析,事务2的等待应该是有两种状况,而出现这两种状况的可能就是事务2的这条语句
insert into test01(id,name,age)values(3,"zzh",22);
复制代码
咱们了解到在记录不存在的时候,若是对此记录进行select...for update语句,该语句会对空位置加gap锁,这个会比较危险,若是咱们的表用的是自增主键,而此时若是查询一个不存在的记录,那会把将来要插入的全部的空隙都加了gap锁,会致使之后表中没法在插入任何数据,这个极其危险。
本篇,咱们介绍了mysql中的锁以及在实践中可能遇到的一些死锁,专门经过几个demo集中分析了一下,对于加锁的分析,在文中所提到的hedecheng的文章中,已经有很深的讲解,因此本文并无对此总结。重点仍是经过一些实际中用到的例子进行实际的分析一下整个过程。重点是插入意向锁和select...for update中的一些加锁的分析。下一篇来专门介绍下mysql的MVCC机制