共享锁(S)、排他锁(X)、意向共享锁(IS)、意向排他锁(IX)的关系

S锁:共享锁 加了S锁的记录,允许其他事务再加S锁,不允许其他事务再加X锁 select…lock in share mode
X锁:排他锁 加了X锁的记录,不允许其他事务再加S锁或者X锁 select…for update



二.意向锁:表锁,相互兼容,表明“某个事务持有了锁、或准备去持有锁”
1、意向锁的存在是为了协调行锁和表锁的关系,支持多粒度(表锁与行锁)的锁并存。



2:
1)意向共享锁(IS锁):事务在请求S锁前,要先获得IS锁
2)意向排他锁(IX锁):事务在请求X锁前,要先获得IX锁



3、例子:事务A修改user表的记录r,会给记录r上一把行级的排他锁(X),同时会给user表上一把意向排他锁(IX),这时事务B要给user表上一个表级的排他锁就会被阻塞。意向锁通过这种方式实现了行锁和表锁共存且满足事务隔离性的要求。



q1:为什么意向锁是表级锁呢?
当我们需要加一个排他锁时,需要根据意向锁去判断表中有没有数据行被锁定(行锁);



(1)如果意向锁是行锁,则需要遍历每一行数据去确认;



(2)如果意向锁是表锁,则只需要判断一次即可知道有没数据行被锁定,提升性能。

q2:意向锁怎么支持表锁和行锁并存?
(1)首先明确并存的概念是指数据库同时支持表、行锁,而不是任何情况都支持一个表中同时有一个事务A持有行锁、又有一个事务B持有表锁,因为表一旦被上了一个表级的写锁,肯定不能再上一个行级的锁。
(2)如果事务A对某一行上锁,其他事务就不可能修改这一行。这与“事务B锁住整个表就能修改表中的任意一行”形成了冲突。所以,没有意向锁的时候,让行锁与表锁共存,就会带来很多问题。于是有了意向锁的出现,如q1的答案中,数据库不需要在检查每一行数据是否有锁,而是直接判断一次意向锁是否存在即可,能提升很多性能。



https://blog.csdn.net/owanttofly/article/details/121194976



一般定位死锁原因第一步就是执行”show engine innodb status“, 查看innodb Standard monitor输出结果,这里面会有数据库最后一次的死锁记录。会记录出现死锁的两个事务,它们分别在等待什么锁,并且手里持有什么锁。mysql在检测到发生死锁的时候,会随机回滚其中的一个事务,从而解开死锁。



innodb级锁按照隔离能力,主要分为共享锁(S锁)和排他锁(X锁)。事务T1的某行上持有S锁,则另一事务T2可以在此行获取S锁,但是不能获取此行的X锁,而如果T1在某行上持有X锁,则另一事务T2,对此行既无法获取S锁,也无法获取X锁。(除了S和X锁外,还有表级锁,分别是意向共享IS锁和意向排他IX锁,这里不做深入)。



按照锁的种类:主要有四种。



1、Record锁:这种锁会在索引上加锁,比如sql为select column_1 from table where column_1=1 for update,且column_1上有索引,则会把colunm_1为1的行都加排它锁,其他事务禁止对此行读和写。



2、Gap锁(间隙锁):这种锁作用在索引记录之间。目的只需要记住:他是为防止其他事务插入间隙(包括防止insert方式插入新数据到间隙,以及update方式将其他行变更到此间隙)。Gap锁可以有效的防止”幻读“(因为这些间隙都被上了锁,其他事务不可能再插入数据到这些间隙中,于是当前事务在连续进行”当前读“时,每次读到的都是相同的记录)。虽然Gap锁只作用在隔离级别为RR及以上的数据库上,但是不意味着隔离等级为RC级别的不会使用,在RC级别,在进行外键约束检测和唯一键约束检测的时候,会使用到Gap锁,而正是这个duplicate-key checking导致了上文出现的死锁发生。



3、Next-Key锁:本质上就是Gap锁和Record锁的结合,锁住索引外还要锁住索引的间隙。再具体一些就是,一个record锁,加上,位于此索引记录前的第一个间隙处的间隙锁。举个简单的例子就是,如果现在有一个索引包含三个值1,3,5,则next-key lock锁,可能锁住的范围就有(-∞,1],(1,3],(3,5],(5,+∞]。同样在next-key lock一般作用在RR隔离等级的数据库,但是当出现在insert时候,检测到唯一键冲突的时候,会在冲突所在唯一索引出和之前的间隙处加Next-key lock.



4、Insert Intention锁(插入意向锁):顾名思义,这个锁是在数据插入之前会加此锁。它是一种轻量的Gap锁,同事也是意向排他锁的一种。它的存在使得多个事务在写入不同数据到统一索引间隙的时候,不会发生锁等待。另外由于它是一种意向插入锁,所以当排他锁已经处于间隙上的时候,根据锁的兼容矩阵,可以知道,意向插入锁必须等待此间隙上的排它锁释放,才能获取。



https://www.jianshu.com/p/7f5d9cf57945
https://my.oschina.net/actiontechoss/blog/3068976



插入意向锁也是类似于gap lock的一种,生效的范围也一致,只是对应锁上相同范围或者有交集的。横轴为已持有,纵轴为后续申请,是否互斥或兼容。



兼容性 插入意向锁 行锁 gap lock
插入意向锁 兼容 互斥 互斥
行锁 兼容 互斥 兼容
gap lock 兼容 兼容 兼容
因此可以看到,在持有gap lock时,在插入的时候如果申请插入意向锁,便会需要等待,而insert on duplicate key的sql在执行时一般就是gap lock和插入意向锁。那么造成死锁的问题就定位到了,肯定是同一时间多个insert事务到来,并且所插入的记录对应的唯一键范围基本一致,所拥有的gap lock和插入意向锁的范围有交集,便可以出现共同持有锁反而造成死锁的问题。



https://www.jb51.net/article/246876.htm
http://t.zoukankan.com/softidea-p-9245163.html
InnoDB还提供了表空间监控器和表监控器,这两个监控器会分别输出共享表空间和InnoDB内部字典的信息,注意 表空间监控器和表的监控器与并发问题没有直接关系



Innodb会每15秒钟监控一次打印数据, 并把这些数据写入到mysql error log日志中去, 这些数据对性能调优很有帮助,但是这样也会降低服务器性能,只有在帮助排除故障时候才建议使用



启用标准Innodb监视器:



SET GLOBAL innodb_status_output=ON;



禁用标准innodb监视器



SET GLOBAL innodb_status_output=OFF;



按需获取标准监视器信息



SHOW ENGINE INNODB STATUS\G



启用innodb 锁定 监视器



SET GLOBAL innodb_status_output=ON;



SET GLOBAL innodb_status_output_locks=ON;



禁用innodb 锁定 监视器



SET GLOBAL innodb_status_output=OFF;



SET GLOBAL innodb_status_output_locks=OFF;



https://baijiahao.baidu.com/s?id=1705250648667242677&wfr=spider&for=pc



Category storage