InnoDB解决幻读的方案——LBCC&MVCC
- 作者: 五速梦信息网
- 时间: 2026年04月04日 13:39
MySQLInnoDBLBCCMVCCInnoDBMyISAM
事务
概念
一个事情由n个单元组成,这n个单元在执行过程中,要么同时成功,要么同时失败,这就把n个单元放在了一个事务之中。举个简单的例子:在不考虑试题正确与否的前提下,一张试卷由多个题目构成,当你答完题交给老师的时候是将一整张试卷交给老师,而不是将每道题单独交给老师,在这里试卷就可以理解成一个事务。
事务的特性:ACID
Atomicity
例:假设你在购物车里添加了两件衣服:上衣和裤子,当你把两件衣服作为一个订单提交支付的时候,要么两件衣服一起支付成功,要么都失败,不可能存在上衣付完钱了,裤子还没付完的情况,反之亦然。
Consistency
例:假设用户A和用户B两者的钱加起来一共是200,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是200,这就是事务的一致性。
Isolation
例:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
Durability
例:我们在操作数据库时,事务提交或者回滚都会直接改变数据库中的值。
事务的操作
startbegincommitrollback
MySQLshow variables like 'autocommit'ONOFF
隔离性引发的并发问题
1)脏读:B事务读取到了A事务尚未提交的数据;
内容
数量
事务的隔离级别
为了解决以上隔离性引发的并发问题,数据库提供了事物的隔离机制。
oraclemysql
serializableserializable
LBCC&MVCC
InnoDBrepeatable readLBCCMVCCLBCCMVCC
LBCC
LBCCLock-Based Concurrent ControlInnoDBInnoDBMyisamRecord LocksGap LocksNext-key Locks

我们将数据库中存储的每一行数据称为记录。则上图中1、5、9、11分别代表id为当前数的记录。对于键值在条件范围内但不存在的记录,叫做间隙(GAP)。则上图中的(-∞,1)、(1,5)...(11,+∞)为数据库中存在的间隙。而(-∞,1]、(1,5]...(11,+∞)我们称之为临键,即左开右闭的集合。
记录锁(Record Locks)
sqlselect ... for updateselectUPDATE
记录锁存在于包括主键索引在内的唯一索引中,锁定单条索引记录。
间隙锁(GAP Locks)
sqlselect ... for updateselectselect
间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害。以下是加锁之后,插入操作的例子:
select * from user where id > 15 for update;
//插入失败,因为id20大于15,不难理解
insert into user values(20,'20');
//插入失败,原因是间隙锁锁的是记录间隙,而不是sql,也就是说`select`语句的锁范围是(11,+∞),而13在这个区间中,所以也失败。
insert into user values(13,'13');
GAP Lockssql
show variables like 'innodb_locks_unsafe_for_binlog';innodb_locks_unsafe_for_binloginnodb_locks_unsafe_for_binlogmy.cnfmy.ini
#在 my.cnf 里面的[mysqld]添加
[mysqld]
innodb_locks_unsafe_for_binlog = 1
临键锁(Next-Key Locks)
sqlselect ... for updateselectselect
插入意向锁并非意向锁,而是一种特殊的间隙锁。
总结
- 如果查询没有命中索引,则退化为表锁;
- 如果等值查询唯一索引且命中唯一一条记录,则退化为行锁;
- 如果等值查询唯一索引且没有命中记录,则退化为临近结点的间隙锁;
- 如果等值查询非唯一索引且没有命中记录,退化为临近结点的间隙锁(包括结点也被锁定);如果命中记录,则锁定所有命中行的临键锁,并同时锁定最大记录行下一个区间的间隙锁。
- 如果范围查询唯一索引或查询非唯一索引且命中记录,则锁定所有命中行的临键锁 ,并同时锁定最大记录行下一个区间的间隙锁。
- 如果范围查询索引且没有命中记录,退化为临近结点的间隙锁(包括结点也被锁定)。
当前读
Locking Readnext-keySQLselect ... lock in share modeselect ... for updateupdatedeleteinsert
MVCC
LBCCLBCCMVCCMVCCMulti-Version Concurremt ControlInnoDBMVCCUndo logRead ViewMVCC
隐藏列
MySQL
InnoDB
undo logInnoDBundo log
ID
(4)实际还有一个删除flag隐藏字段,既记录被更新或删除并不代表真的删除,而是删除flag变了。
undo log
每当我们要对一条记录做改动时(这里的改动可以指INSERT、DELETE、UPDATE),都需要把回滚时所需的东西记录下来, 比如:
InnoDBundo logSELECTundo log
DB_ROLL_PTR
例
insert undoUndo Log Segment
undo logundo log
Read View
selectfor updateselectidmin_ididmax_idreadviewidreadview
MVCCMVCCMVCCREAD COMMITTEDREPEATABLE READMVCCREAD UNCOMMITTEDSERIALIZABLERead Viewselectselectupdate
RC和RR隔离级别下的快照读和当前读:RC隔离级别下,快照读和当前读结果一样,都是读取已提交的最新;RR隔离级别下,当前读结果是其他事务已经提交的最新结果,快照读是读当前事务之前读到的结果。RR下创建快照读的时机决定了读到的版本。
InnoDBRead View
Read Viewselectmin_idmax_idread view

版本链比对规则:
- 如果落在绿色部分(trx_id<min_id),表示这个版本是已经提交的事务生成的,这个数据是可见的;
- 如果落在红色部分(trx_id>max_id),表示这个版本是由将来启动的事务生成的,是肯定不可见的;
- 如果落在黄色部分(min_id<=trx_id<=max_id),那就包含两种情况:
a.若row的trx_id在数组中,表示这个版本是由还没提交的事务生成的,不可见;如果是自己的事务,则是可见的;
b.若row的trx_id不在数组中,表示这个版本是已经提交了的事务生成的,可见。
testaccountaccountundo log
//test表中数据
id=1,c1='11';
id=5,c1='22';
//account表数据
id=1,name=‘lilei’;
sqlselectreadview[100,200],300lilei300trx_id=300readviewselecttrx_id=100readview[100,200],300lilei300trx_id=100readviewtrx_id=300selecttrx_id=100InnoDBreadviewreadview[100,200],300lilei300
updatereadview
InnoDBselectreadview[200],300lilei2
updateupdatetrx_idtrx_idrecord headerdeleted_flagtruedelete_flagtrue
undo logundo logread viewundo log
以上就是今天的全部内容了,如果你感兴趣的话,可以关注微信公众号“阿Q说代码”!也可以加我微信qingqing-4132,期待你的到来!
- 上一篇: InnoDB在MySQL默认隔离级别下解决幻读
- 下一篇: InnoDB的锁机制浅析(三)—幻读
相关文章
-
InnoDB在MySQL默认隔离级别下解决幻读
InnoDB在MySQL默认隔离级别下解决幻读
- 互联网
- 2026年04月04日
-
Innodb之拷贝InnoDB表从一服务器到另一台服务器
Innodb之拷贝InnoDB表从一服务器到另一台服务器
- 互联网
- 2026年04月04日
-
inotify+rsync实现实时同步(附解决crontab中无法执行python脚本的问题)
inotify+rsync实现实时同步(附解决crontab中无法执行python脚本的问题)
- 互联网
- 2026年04月04日
-
InnoDB的锁机制浅析(三)—幻读
InnoDB的锁机制浅析(三)—幻读
- 互联网
- 2026年04月04日
-
InnoDB:Lock & Transaction
InnoDB:Lock & Transaction
- 互联网
- 2026年04月04日
-
Innodb 中 RR 隔离级别能否防止幻读?
Innodb 中 RR 隔离级别能否防止幻读?
- 互联网
- 2026年04月04日








