Innodb存储引擎--锁整理

Innodb的锁,保障了事务的隔离性;对索引(聚集索引组织表)加锁,Oracle是对数据块(堆表)加锁

何登成的文章_基础
何登成的文章_进阶

锁类型

innodb支持多粒度锁:记录级锁和表级锁;
为了支持这种多粒度,加入意向锁(intention lock),
意向锁是表级锁,提示事务对此表记录加的记录锁类型。

兼容 X IX S IS
X
IX
S
IS

1、要想获得S锁,必须先取得IS或者更强的锁
2、要想获得X锁,必须先取得IX锁

  • 意向锁不会阻塞任何操作,除非是全表请求(alter, lock table ...)
  • 意向锁是完全兼容的,因为是表级别的,若不兼容,则innodb的行锁无从谈起
    事务1对表a的某些记录进行写操作,事务2相对表a的某另一些记录进行写操作,两者都有IX操作,若不兼容,直接退变成Myisam的表锁形式了
  • X, S 的兼容场景,针对的是同一记录区间的读写,这样就理解上面的兼容性

锁算法(这是锁算法,不是锁类型)

Record lock:This is a lock on an index record.
记录锁一定是锁索引记录,即使无索引,也会使用innodb的隐藏的聚集索引

Gap lock: *This is a lock on a gap * between index records, or a lock on the gap before the first or after the last index record.
间隙锁唯一索引不会用到(联合唯一索引前缀过滤仍会使用),无索引和非唯一索引会使用,锁记录的前后区间

Gap锁特性:

不同事务对同一区间的不同记录进行插入操作,两者不冲突
gap 区间的一条记录被删除, gap 锁要合并
gap s == gap x ,且兼容。只阻塞插入区间操作

Next-key lock:This is a combination of a record lock on the index record and a gap lock on the gap * before * the index record.
举例:
(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity) 退化为gap lock,信息展示next_key lock

X type record lock gap lock next_key lock
record lock
gap lock
next_key lock

不可重复读(幻读)

一个事务内,对同一数据集合连续查询(包括非锁定读),另外一个事务对此数据集合进行了DML,本事务内结果是一致的。但不保障查询之间,本事务的DML(会有“幽灵”输出)的场景。注意,innodb读取的是查询开始的快照,不是事务开启时的快照

锁案例

CREATE TABLE testlock (
a int(11) NOT NULL DEFAULT '0',
b int(11) DEFAULT NULL,
PRIMARY KEY (a),
KEY b (b)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
select * from testlock;
+----+------+
| a | b |
+----+------+
| 2 | 1 |
| 5 | 3 |
| 6 | 5 |
| 10 | 8 |
+----+------+

  • 有值加锁
    select * from testlock where b=3 for update

由图例可以看出:
索引b,加了next_key lock (1,3] 和 gap lock(3,5)
主键a,加了一个record lock a=5

有值加锁
  • 无值加锁
    select * from testlock where b=2 for update
    由图例可以看出:
    索引b,加了gap lock (1,3)
    无值加锁.png
  • 临界加锁
  • select xxxx from where b xxx for update
    select * from testlock where b=8 for update
    (5,8],(8, +∞)。
    select * from testlock where b>8 for update
    select * from testlock where b>80 for update
    锁全表
临界加锁
  • delete from where b xxx
    delete from testlock where b=8
    此种情况,与上面的一致,加锁(5,8],(8, +∞)。截图与上面的模式相同
    delete from testlock where b> 8
    此种情况,加next_key lock (8, +∞)。图例准确
  • upate where b xxx
    update testlock set a=9 where b=6
    update testlock set b=10 where b=6
    update涉及对索引的自身值得改写操作,存在锁分裂的情况,不一而足

当然,跟组合四:[id无索引, Read Committed]类似,这个情况下,MySQL也做了一些优化,就是所谓的semi-consistent read。semi-consistent read开启的情况下,对于不满足查询条件的记录,MySQL会提前放锁。针对上面的这个用例,就是除了记录[d,10],[g,10]之外,所有的记录锁都会被释放,同时不加GAP锁。semi-consistent read如何触发:要么是read committed隔离级别;要么是Repeatable Read隔离级别,同时设置了innodb_locks_unsafe_for_binlog 参数。更详细的关于semi-consistent read的介绍,可参考我之前的一篇博客:MySQL+InnoDB semi-consitent read原理及实现分析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容