MYSQL数据库Innodb 引擎mvcc锁实现原理
InnoDB是MySQL数据库的默认存储引擎,实现了被广泛使用的多版本并发控制(MVCC)锁机制,这使得InnoDB的并发处理能力比其他存储引擎更优秀。本文将重点讲解InnoDB的MVCC锁实现原理。
MVCC介绍
MVCC为多版本并发控制(Multi-Version Concurrency Control)的缩写。MVCC有时也称作Snapshot Isolation,即快照隔离级别。MVCC是为数据库并发控制而设计的,本质上是通过在每个事务中创建某个时间点的数据库快照来实现数据库隔离的。在已有的快照中读取可以避免由于读写同时存在而导致的资源竞争问题,这样就可以有效提高并发处理能力。
InnoDB的MVCC实现
在InnoDB的实现中,每一行记录都有多个版本。每个版本都有自己的版本号,这个版本号实际上由系统版本号(system version number)和事务编号(transaction ID)两个部分组成。其中,系统版本号是在之前任何一个事务操作InnoDB表时从磁盘读取的系统状态号,每当有事务提交时,状态号都会递增。事务编号是在每个事务开始时自动分配的。
当事务开始时,InnoDB会为每个事务分配一个唯一的事务编号,用于记录该事务对应的快照时间。InnoDB允许在一个事务中读取之前提交的数据快照,这样的查询也被称为快照读(Snapshot Read)。
在InnoDB的MVCC实现中,有两种类型的快照读:一种是一般性查询,另一种是当前读。现在将逐一介绍它们。
- 一般性查询(Non-Locking Read)
一般性查询是InnoDB的MVCC最基本的查询操作。它并不会加任何锁,也不会对其他事务带来任何阻塞。但它需要选择合适的版本号,根据版本号去快照中去读取数据。即使在同一事务中多次执行相同的查询,读取的数据结果也是不变的。
举个例子:一个表包含一条记录,记录的ID为1,当前有两个事务,分别为T1和T2:
在T1中,执行select * from table where id=1;
在T2中,执行update table set value='new value' where id=1;
那么在T1中,删除操作前,该表的记录快照是:(id=1, value=old value, sys version=1.1, trx id=T2)
在T1中,快照读会选择版本号1.1去获取该行记录,结果还是旧值old value。
- 当前读(Locking Read)
当前读会锁住一行记录,为查询之后的更新操作或删除操作创建MVCC多版本。执行当前读操作时,会获取行锁(Shared Lock、Exclusive Lock 以及Update Lock三种类型)来保证数据一致性。
在InnoDB中,行锁既可以由自动增加的事务id(auto-inc transaction id,即AIT)来生成。也可以是由事务直接指定的事务id来生成。事务可以通过事务隔离级别的设置来指定不同级别的行锁操作方式。
举个由当前读操作产生的示例:一个表包含一条记录,记录的ID为1,当前有两个事务,分别为T1和T2:
在T1中,执行select * from table where id=1 for update;
在T2中,执行update table set value='new value' where id=1;
那么在T1中,此时行锁会锁住记录ID为1的这一行,也因此可以通过当前读或当前写来解决并发问题。
总结
InnoDB的MVCC锁机制是实现并行执行的关键。通过对事务快照的创建,InnoDB保证了并发执行的正确性和完整性。同时,当前读操作可以对行记录进行锁定,保证同一事务中读取的数据版本是最新的。
示例1中,T1查询了表中ID为1的记录,因为是快照读,所以读取的数据是T1开启前提交的数据快照。示例2中,T1为了避免数据被其他事务更改,选择了行锁,锁定了表中ID为1的记录。这样在T2中执行更新操作时,将会等待T1事务完成释放锁才能执行。
以上是对InnoDB的MVCC锁实现原理的详细讲解。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:MYSQL数据库Innodb 引擎mvcc锁实现原理 - Python技术站