InnoDB-Lock/Transaction

并发,重头戏

Locking

Shared and Exclusive Locks

InnoDB默认使用的是行级锁(row-level locking),具体分成两种,shared(s) locks和exclusive(x) locks。前者用于读,后者用于更改与删除。

  • T1 s lock->T2 s lock get immediately
  • T1 s lock->T2 x lock hold on
  • T2 x lock->T2 any lock hold on

Intention Locks

意向锁(intention locks)是一种表锁,用于告诉其他用户该事务在之后的操作中会对行进行什么类型的锁。

  • Intention shared lock(IS):意向共享锁
  • Intention exclusive lock(IX):意向排他锁

使用方法

  • 事务在申请行级共享锁之前,需要申请IS锁
  • 事务在申请行级排他锁之前,需要申请IX锁

冲突关系

下表为普通的表锁与意向锁之间的冲突关系,一旦出现冲突,只有当前的锁被释放才能够进行进一步的操作。此外,意向锁只会和表锁产生冲突,行锁粒度的冲突交由行锁去处理,所以IS和IX可以共存。

x IX S IS
X × × × ×
IX × ×
S × ×
IS ×

Record Locks

用于锁定索引本身的锁,不论是主索引还是辅助索引。例如

1
2
SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;
用于锁定所有c1为10的记录,防止其他事务插入/删除/修改c1为10的数据

Gap Locks

Record Locks的进阶版,选中一个范围内的数据,不允许其他事务在这个范围内进行增删改查。Gap Locks可用于单索引,多索引,甚至没有索引也是可以的。

1
SELECT c1 FROM t WHERE c1 BETWEEN 10 AND 20 FOR UPDATE;

对于读unique列的操作,加上Gap Locks是多此一举的行为。多个Gap Locks是可以被Merge的,在真正的修改操作进行前,并不会导致任何冲突。

Next-Key Locks

Next-Key Locks是Record Locks和Gap Locks的复合体。该操作并不需要手动指定锁的范围,而是锁住相关行的前/后一行之间的间隙。

Insert Intention Locks

Gap锁的一种,用于表示该事务会在一定范围内插入数据,以提高并行插入的能力,如果两个事务的Insert Intention Locks没有重叠区域,则把他们一起运行也不会对系统有什么不良影响。

AUTO-INC Locks

特殊的表锁,用于自增主键

Predicate Locks for Spatial Indexs

空间索引(地理数据之类的二维索引)不在考虑范围内,所以忽略

Transaction

Transaction Isolation

Read Uncommited

完全不加锁,一切随缘,脏读幻读都有可能

Read Committed

单次读的一致性有保障,但一个事务中的所有读的一致性没有保障,有可能出现幻读

  • 读一般只会上行锁,只有在外键和重复键检查的时候才会用Gap Locks
  • 对于删除和修改,依然使用行锁,在Where筛选结束后,将会释放那些无关的行,虽然概率小,但还是会死锁
  • 要修改已经被锁上的行时,MySQL会先读一下,初步确定是否符合Where条件,符合条件后又再次进行上锁与读取的操作

Repeatable Read(default)

一个事务的读一致性有所保障

  • Unique Index,只会锁一行
  • 其他的,上Gap Locks/Next-Key Locks

Serializable

最高强度的隔离,会在每一句SELECT之后加上’FOR SHARE’

AutoCommit, Commit&Rollback

AutoCommit

每个SQL语句都会构成一个事务,没有错误的事务被执行后都会被Commit,错误的执行会被Rollback

Commit

意味着该事务的操作会被其他事务看到

Consistent Nonlocking Reads

使用MVCC+s locks让多个事务同时读写数据,而且不会互相干扰,具体效果依据隔离程度决定。在以下情况,该功能不可用

  • DROP TABLE
  • ALTER TABLE

Locking Reads

普通的SELECT可能隔离强度不足,手动加锁

  • SELECT FOR SHARE
  • SELECT FOR UPDATE

Deadlocks

原因

死锁是由写操作产生的,所以改变隔离状态不会让死锁问题得到改善。

  • 写粒度要小
  • 多用事务,少用表锁

Detection and Rollback

  • 碰撞检测(有向图找环);如果出现超过200个事务在等待;也可以关掉使用事务超时进行判断
  • 选择插入/更新/删除行数最小的事务回滚
  • InnoDB回滚时,会释放所有的锁。但是,存在个别情况,例如语句执行失败后,仅仅回滚这一条语句,则不会释放该语句的锁,因为InnoDB不存储SQL语句与锁的对应关系
  • 如果是SELECT在事务中调用预先设置好的内建函数,而且出现语句失败,则该语句会回滚,如果又进一步手动执行ROLLBACK,会导致整个事务一起回滚

Scheduling

Contention-Aware Transaction Scheduling(CATS),基于权重决定事务优先关系,权重由以下内容决定

  • 为阻塞事务数目多的事务更高的权重
  • 阻塞数目一样多,等待时间长的更高权重

ref