1、乐观锁与悲观锁
  1. 数据库的乐观锁与悲观锁是什么?
  2. 数据库的乐观锁与悲观锁如何实现?

确保在多个事务同时存取数据库中同一数据时,不破坏事务的隔离性和统一性以及数据库统一性,乐观锁和悲观锁是并发控制主要采用的技术手段。

悲观锁 - 假设会发生并发冲突,屏蔽一切可能违反数据库完整性的操作。

  • 在查询完数据的时候就把事务锁起来,直到提交事务(COMMIT)
  • 实现方式:使用数据库中的锁机制

乐观锁 - 假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。

  • 在修改数据的时候把事务锁起来,通过 version 的方式进行锁定
  • 实现方式:使用 version 版本或时间戳

2、行级锁与表级锁
  1. 什么是行级锁和表级锁?
  2. 什么时候用行级锁?什么时候用表级锁?

从数据库的锁粒度来看,MySQL 中提供了两种锁粒度:行级锁和表级锁。

表级锁(table lock) - 锁定增张表。用户对表进行写操作前,需要先获得写锁,这会阻塞其他用户对该表的所有读写操作。只有没有写锁时,其他用户才能获得读锁,读锁之间不会互相阻塞。
行级锁(row lock) - 仅对指定的行记录进行加锁,这样其他进程还是可以对同一张表中的其他数据进行操作。

二者需要权衡:

  • 锁定的数据量越小,锁竞争的发生频率就越小,系统的并发程度就越高。
  • 锁粒度越小,系统开销越小。

InnoDB中,行锁是通过给索引上的索引项加锁来实现的。如果没有索引InnoDB将会通过隐藏的聚簇索引来对记录加锁。

3、读写锁
  1. 什么是读写锁?

写锁和读锁的关系,简言之:独享锁存在,其他事务就不能做任何操作。
InnoDB下的行锁、间隙锁、next-key 锁统统属于独享锁。

独享锁(Exclusive) - 简写为X锁,又称写锁。使用方式:SELECT...FOR UPDATE
共享锁(Shared) - 简写为S锁,又称读锁。使用方式:SELECT ... LOCK IN SHARE MODE

4、意向锁
  1. 什么是意向锁?
  2. 意向锁有什么作用?

意向锁是InnoDB自动加的,不需要用户手动干预。
意向锁的作用:当存在表级锁和行级锁的情况下,必须先申请意向锁(表级锁,但不是真的加锁),再获得行级锁。使用意向锁(Intention Locks)可以更容易的支持多粒度封锁。

5、MVCC
  1. 什么是 MVCC?
  2. MVCC 的原理是什么?
  3. MVCC 有什么用?解决了什么问题?

多版本并发控制(Multi-Version Concurrency Control, MVCC)是InnoDB存储引擎实现隔离界别的一种具体方式,用于实现读已提交和可重复读这两种隔离级别。而读未提交隔离级别总是读取最新的数据行,要求很低,无需使用MVCC。可串行化隔离级别需要对所有读取的行都加锁,单纯使用 MVCC 无法实现。

MVCC的思想是:

  • 保存数据在某个时间点的快照。写操作(DELECT、INSERT、UPDATE)更新最新的版本快照,而读操作去读旧版本快照,没有互斥关系,这一点和CopyOnWrite类似。
  • 脏读和不可重读最根本的原因是事务读取到其他事务未提交的修改。在事务进行读取操作时,为了解决脏读和不可重复问题,MVCC规定只能读取已经提交的快照。当然一个事务可以读取自身未提交的快照,这不算脏读。

6、Next-Key锁

Next-Key 锁是 MySQL 的InnoDB存储引擎的一种锁实现。

MVCC 不能解决幻读问题,Next-Key 锁就是为了解决幻读问题。在可重复读(REPEATABLE READ)隔离级别下,使用 MVCC + Next-Key 锁可以解决幻读问题。

另外,根据针对 SQL 语句检索条件的不同,加锁又有以下三种情形需要我们掌握

  • Record Lock - 行锁对索引项加锁,若没有索引则使用表锁。
  • Gap Lock - 对索引项之间的间隙加锁。锁定索引之间的间隙,但是不包含索引本身。例如当一个事务执行以下语句,其他事务就不能在 t.c 中插入 15。SELECT c FROM t WHERE c BETWEEN 10 AND 20 FOR UPDATE
  • Next-Key Lock - 它是Record LockGap Lock的结合,不仅锁定一个记录上的索引,也锁定索引之间的间隙。它锁定一个前开后闭区间。

索引分为主键索引和非主键索引两种,如果一条SQL语句操作了主键索引,MySQL就会锁定这条主键索引;如果一条语句操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引。在UPDATE、DELETE操作时,MySQL不仅锁定WHERE条件扫描过的所有索引记录,而且会锁定相邻的键值,即所谓的Next-Key Lock

当两个事务同时执行,一个锁住了主键索引,在等待其他相关索引。另一个锁定了非主键索引,在等待主键索引。这样就会发生死锁。发生死锁后,InnoDB一般都可以检测到,本使一个事务释放锁回退,另一个获取锁完成事务。