mysql mvcc 锁 关系
多版本并发控制(MVCC)是一种用于数据库并发控制的机制,它可以在保证数据一致性的同时,提高数据库的并发性能。下面结合 MVCC 机制,详细阐述常见的四种事务隔离级别(读未提交、读已提交、可重复读、串行化)与各种锁(共享锁、排他锁、记录锁、间隙锁、临键锁)之间的关系。
读未提交(Read Uncommitted)
- MVCC 机制:在该隔离级别下,MVCC 机制基本不发挥作用。因为此隔离级别允许一个事务读取另一个未提交事务的数据,它更侧重于提高并发性能,而不是通过 MVCC 来保证数据的一致性。事务在读取数据时,不会基于 MVCC 去判断数据版本,而是直接读取最新的数据,无论该数据是否已经提交。
- 共享锁(S 锁)和排他锁(X 锁)
- 此隔离级别对锁的使用进行了极大程度的弱化。一般情况下,普通的读操作不会加共享锁,写操作(如
UPDATE
、DELETE
、INSERT
)虽可能会对受影响的行加排他锁,但这种锁的限制作用相对较弱,因为即使有排他锁存在,其他事务也能读取未提交的数据,会导致脏读。
- 此隔离级别对锁的使用进行了极大程度的弱化。一般情况下,普通的读操作不会加共享锁,写操作(如
- 记录锁、间隙锁和临键锁
- 通常不会使用记录锁、间隙锁和临键锁。由于不依赖 MVCC 来保证数据一致性,也不需要这些锁来防止不可重复读和幻读问题。
读已提交(Read Committed)
- MVCC 机制:MVCC 在该隔离级别中发挥重要作用。普通的
SELECT
查询采用快照读,基于 MVCC 读取已提交的数据版本。每个语句执行时,都会生成一个新的快照,这使得在同一个事务内不同时刻执行相同的查询可能会得到不同的结果,从而可能出现不可重复读的问题。 - 共享锁(S 锁)和排他锁(X 锁)
- 共享锁:普通的
SELECT
查询默认不会加共享锁,而是利用 MVCC 进行快照读。但当使用SELECT ... LOCK IN SHARE MODE
时,会对查询结果集的行加共享锁,允许其他事务同时读取这些行,但阻止其他事务对这些行加排他锁进行修改。 - 排他锁:
UPDATE
、DELETE
、INSERT
语句以及SELECT ... FOR UPDATE
会对受影响的行加排他锁。并且,这些锁是语句级别的,即锁只在语句执行期间有效,语句执行完毕后锁就会释放。
- 共享锁:普通的
- 记录锁、间隙锁和临键锁
- 记录锁:在执行
SELECT ... FOR UPDATE
或写操作时,会对读取或修改的行加记录锁。 - 间隙锁和临键锁:一般不会使用间隙锁和临键锁。因为 MVCC 的快照读机制和语句级别的锁控制,使得该隔离级别允许幻读的存在,无法阻止其他事务在查询范围的间隙插入新记录。
- 记录锁:在执行
可重复读(Repeatable Read)
- MVCC 机制:MVCC 是该隔离级别实现可重复读特性的关键。在事务开始时,会创建一个全局的快照,事务内的所有
SELECT
查询都基于这个快照进行,保证在同一个事务内多次读取相同数据的结果是一致的。不过,对于当前读操作(如SELECT ... FOR UPDATE
、UPDATE
、DELETE
),MVCC 机制与锁机制共同作用来保证数据的一致性。 - 共享锁(S 锁)和排他锁(X 锁)
- 共享锁:普通
SELECT
查询采用快照读,不会加共享锁。使用SELECT ... LOCK IN SHARE MODE
时,会对查询结果集的行加共享锁,防止其他事务对这些行加排他锁进行修改。 - 排他锁:
UPDATE
、DELETE
、INSERT
语句以及SELECT ... FOR UPDATE
会对受影响的行加排他锁。这些锁会在事务结束(提交或回滚)时才释放。
- 共享锁:普通
- 记录锁、间隙锁和临键锁
- 记录锁:在执行
SELECT ... FOR UPDATE
或写操作时,会对读取或修改的行加记录锁。 - 间隙锁:当进行范围查询(如
SELECT ... FOR UPDATE
或写操作涉及范围条件)且查询条件没有精确匹配到所有记录时,会对查询范围对应的间隙加上间隙锁,防止其他事务在这些间隙插入新记录。这是为了弥补 MVCC 在处理范围插入时可能出现幻读的不足。 - 临键锁:临键锁是记录锁和间隙锁的组合。在可重复读隔离级别下,对于索引记录,InnoDB 通常使用临键锁来防止幻读。例如,对唯一索引进行等值查询时,如果记录存在,使用记录锁;如果记录不存在,使用间隙锁;对于普通索引,一般使用临键锁。
- 记录锁:在执行
串行化(Serializable)
- MVCC 机制:在串行化隔离级别下,MVCC 机制基本不发挥作用。因为该隔离级别要求事务串行执行,所有的读写操作都需要排队进行,以保证数据的绝对一致性。它不依赖 MVCC 的多版本特性来处理并发,而是通过严格的锁机制来实现事务的隔离。
- 共享锁(S 锁)和排他锁(X 锁)
- 共享锁:普通的
SELECT
查询会自动对查询结果集的行加共享锁,保证在当前事务读取数据期间,其他事务不能对这些数据加排他锁进行修改。 - 排他锁:
UPDATE
、DELETE
、INSERT
语句会自动对受影响的行加排他锁。由于事务是串行执行的,任何事务的读写操作都需要等待前面事务释放相应的锁,并发性能最差,但能完全避免脏读、不可重复读和幻读问题。
- 共享锁:普通的
- 记录锁、间隙锁和临键锁
- 在串行化隔离级别下,记录锁、间隙锁和临键锁都会被使用,以确保事务之间的完全隔离。无论是读取还是修改数据,都会通过这些锁来保证同一时间只有一个事务可以访问特定的数据资源,从而实现事务的串行执行。
综上所述,MVCC 机制和锁机制在不同的事务隔离级别中相互配合,共同影响着数据库的并发性能和数据一致性。较低的隔离级别更依赖 MVCC 来提高并发性能,而较高的隔离级别则更强调锁机制来保证数据的严格一致性。