InnoDB引擎中的锁
一、锁的类型
1、共享锁(S lock lock in share mode)行锁
2、排他锁(X lock for update)行锁
兼容性 只有S锁和S锁兼容 其他情况均阻塞
S | X | |
S | 兼容 | 不兼容 |
X | 不兼容 | 不兼容 |
3、意向锁(Intention Lock)支持多粒度锁 由上到下依次是 库->表->页->行。如果要对细粒度上锁,则必须先对粗粒度上锁。InnoDB只支持表级别的意向锁,目的是获取某几行的锁(?意向锁怎么用)
3.1意向共享锁(IS Lock) 事务获取一张表某几行的共享锁
3.2意向排他锁(IX Lock) 事务获取一张表某几行的排他锁
兼容性 innodb支持的是行级锁,意向锁其实不会阻塞除全表扫描以外的任何请求
IS | IX | S | X | |
IS | 兼容 | 兼容 | 兼容 | 不兼容 |
IX | 兼容 | 兼容 | 不兼容 | 不兼容 |
S | 兼容 | 不兼容 | 兼容 | 不兼容 |
X | 不兼容 | 不兼容 | 不兼容 | 不兼容 |
二、一致性锁定读(对读加锁)
innodb默认事务隔离级别是可重复读,默认的select操作不会对读取行加锁(MVCC),但是在某些业务场景下,咱们需要对读也加锁。
select ... lock in share mode 对读加S锁
select ... for update 对读加X锁
注意:即使对读的行加了X锁之后,默认的select 查询也不会被阻塞(MVCC)
三、自增长与锁
自增长是一种常见属性,经常用自增id做表的主键,对于记录的插入,插入操作会先执行 select MAX(auto_inc_col) from table for update 来获取自增id 的最大值然后加一,这个实现方式叫 AUTO-INC Locking ,是一种特殊的表锁,它不会等待事务提交才释放锁,而是完成insert 之后立即释放,从而提高并发。但是如果一个事务有大量的insert,还是会阻塞其他事务,所有后面优化了,innodb提供一个参数innodb_autoinc_lock_mode来控制自增模式,默认为1,枚举值为0 - AUTO-INC Locking(老版的处理方式 尽量别用),1-互斥量 2- 互斥量
四、外键与锁
外键即使不显示的加索引,mysql也会自动加一个索引,避免表锁。对外键值的insert和update操作,会先去查父表,并且为了一致性,不能用mvcc,会自动加一个S锁。如果父表已经加了一个X锁,就会阻塞。
五、锁的算法
5.1 Record Lock :真正的行锁,只锁一行
5.2 Gap Lock :间隙锁,锁一个范围区间
5.3 Next-Key Lock :Record + Gap 锁一个范围和记录本身
innodb默认使用Next-Key Lock ,但是对于含有唯一索引的锁,会退化为Record Lock,提高并发。innodb还会对辅助索引下一个键值加Gap Lock。
例如 某列字段z的值是 1,3,5,7,9 执行 select * from table where z = 3 for update 首先会Next-Key Lock 会锁住 (1,3] ,同时还会用Gap Lock 锁住 (3,5)
所以在另一个事务执行 insert into table select 5会被阻塞 。加Gap lock 是为了解决幻读。innodb执行insert操作,会先检测插入的下一条记录是否有锁,如果不锁(3,5),则insert 3 检查下一个记录没有被锁,就插入进去了,这时在上一个事务中,如果再查询select * from table where z = 3 就会多一条记录了,产生幻读。