MySQL InnoDB存储引擎(三):锁及事务模型
对于开发人员而言,对于锁和事务不会陌生。为了避免多线程同时读写共享数据发生竞争的问题,因此,锁是一种比较常用的方式。而事务的定义,主要体现在其基本特性:原子性,一致性,隔离性,持久性。之前的一篇文章有所提到过。但我相信很多开发人员对事务和锁的理解是不够深入的,包括我自己,始终觉得好像很容易回答,又答不出所以然,平常也应该有人问某条SQL会加什么锁呢,为什么我在方法上加了@Transactional就发生死锁了呢?本文将阐述InnoDB存储引擎中的锁及事务模型相关的细节,希望能帮助开发人员了解InnoDB如何有效处理并发事务等机制。
InnoDB锁(InnoDB Locking)
在InnoDB中有多种类型的锁,分别适用于不同的场景,如共享/排它锁,意向锁,记录锁等,下面将逐一对其进行阐述。
共享/排它锁(Shared and Exclusive Locks)
InnoDB实现了两种类型的标准行级锁:共享锁(S)和排它锁(X)。下面分别阐述其作用及区别:

如图中所示,事务1和事务2并发开启事务(操作1,2),并通过语句LOCK IN SHARE MODE对同一行记录请求了共享锁(操作3,4),此时,事务3开启(操作5),并尝试更新同一行记录(操作6),但此时会被事务1和事务2持有的共享锁阻塞,直到事务1和事务2均提交了事务(操作7,8),事务3的更新操作得以执行,并提交事务(操作9)。

如图中所示,事务1并发开启事务(操作1),并通过UPDATE语句请求到了行记录的排它锁(操作2);此时,事务2对同一行记录进行读操作(操作3),由于InnoDB的默认事务隔离级别为REPEATABLE READ,因此该操作得以执行;事务3开启事务(操作4),并尝试修改同一行记录(操作5),但该行记录的排它锁已被事务1获取,因此被阻塞,直到超时重新开启事务,此时,提交事务1,事务3的更新操作(操作6)方可执行。
意向锁(Intention Locks)
InnoDB支持多粒度锁,允许行锁和表锁共存,为了支持这种多粒度锁的场景,InnoDB提出了另一种锁--意向锁。意向锁属于表级锁,用来表明事务想要在表中的行上获取什么类型的锁(共享或独占),不同的事务可以在同一个表上获取不同类型的意向锁,但是第一个事务获取表上的意向排它锁(IX)可以阻塞其他事务获取该表上的任何S或X锁。相反,获取表上的意向共享锁(IS)的第一个事务将阻塞其他事务获取表上的任何X锁。两阶段过程允许按顺序解决锁定请求,而不阻塞锁定和对应的兼容操作。InnoDB这样定义了上述两种意向锁:
意向锁同时需要遵循以下协议: