当前位置: 首页 > 科技观察

MYSQL中乐观锁实现(MVCC)简析

时间:2023-03-12 17:16:00 科技观察

什么是MVCMVCC即Multi-VersionConcurrencyControl,中文翻译称为多版本并发控制。MVCC解决了什么问题?众所周知,在MYSQL中,MyISAM使用表锁,InnoDB使用行锁。InnoDB的事务分为四个隔离级别。REPEATABLEREAD默认的隔离级别要求两个不同的事务不能相互影响,也可以支持并发。这是悲观锁做不到的,所以REPEATABLEREAD使用乐观锁,用MVCC来实现乐观锁。正是因为有了MVCC,InnoDB才有了强大的事务处理能力。MVCC的具体实现分析InnoDB的MVCC,是通过在每行记录后面保存两个隐藏列来实现的。这两列分别保存了这一行的创建时间,一列保存了该行的删除时间。这里存储的不是实际的时间值,而是系统版本号(可以理解为交易的ID)。每启动一个新的交易,系统版本号会自动递增,并以交易开始时的系统版本号作为交易ID。ID。让我们看看MVCC在REPEATABLEREAD隔离级别下是如何运行的。先建表:createtableyang(idintprimarykeyauto_increment,namevarchar(20));假设系统的版本号从1开始,INSERTInnoDB将当前系统版本号保存为每个新插入行的版本号。最后一个交易ID是1:starttransaction;insertintoyangvalues(NULL,'yang');insertintoyangvalues(NULL,'long');insertintoyangvalues(NULL,'fei');commit;数据中对应的表如下(下面两列是隐藏列,我们通过查询语句是看不到的)SELECTInnoDB会根据以下两个条件来检查每一行记录:InnoDB只会查找版本早于当前事务版本(即该行的系统版本号小于或等于事务的系统版本号)的数据行,保证了事务读取的行要么存在于事务开始,或由事务本身插入或修改。行的删除版本未定义或大于当前事务版本号(这样可以保证事务读取的行在事务开始前不被删除),只有同时满足条件1和条件2的记录才能作为查询结果返回。DELETEInnoDB会为每行删除保存当前系统的版本号(事务的ID)作为删除标识。看下面具体实例分析:第二个事务,ID为2:starttransaction;选择*来自杨;选择*来自杨;犯罪;假设1:假设执行这个事务ID为2的进程在(1)中,刚执行完(1),此时另一个事务ID为3向这个表中插入一条数据;第三个事务ID是3;starttransaction;insertintoyangvalues(NULL,'tian');commit;this时间表中的数据如下:然后在事务2中执行(2),由于id=4的数据的创建时间(事务ID为3),所以当前事务的ID为2,InnoDB会只查找事务ID小于数据行等于当前事务ID,所以id=4的数据行在事务2中不会在(2)中检索到。事务2中的两个select语句检索到的数据是如下:假设2假设在执行事务ID为2的过程中,只执行(1),假设事务执行事务3,然后执行事务4;第四笔交易:starttransaction;deletefromyangwhereid=1;commit;此时数据库中的表如下:然后执行事务ID为2的事务(2),根据SELECT检索条件可知,会检索到创建时间(事务ID为2)的行创建的交易)小于当前交易ID和删除时间(delete除了交易的ID)大于当前交易的行,上面已经提到了id=4的行,而id=1的行大于当前交易的ID,因为删除时间(删除事务的ID)大于当前事务的ID,所以事务2的(2)select*fromyang也会取出id=1的数据。因此,事务2中两条select语句取出的数据如下:UPDATEInnoDB执行UPDATE,实际上是插入了一行新记录,保存的是当前事务的ID,将当前事务ID保存到要更新的行的删除时间。假设三:假设在执行完事务2的(1)后,其他用户执行事务3和4,此时有A用户对该表进行UPDATE操作:第五个事务:starttransaction;updateyangsetname='Long'whereid=2;commit;根据update的更新原则:会生成新的一行,同时删除要修改的列将这个事务ID加入时间列,得到表如下:继续执行事务2的(2),和根据select语句的查找条件得到下表:仍然得到与事务2(1)中的select相同的结果。