mysql mvcc 作用_Mysql的MVCC到底是啥?

本文详细介绍了MVCC(多版本并发控制)的概念及其实现原理。解释了MVCC如何通过保存数据的不同版本来避免幻读现象,并允许在高并发环境中进行非阻塞读取。此外,还探讨了InnoDB存储引擎下的行锁、间隙锁和Next-Key Lock机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

正如标题,MVCC到底是什么?

MVCC:多版本并发控制。把数据库的行锁与行的多个版本结合起来,实现并发控制。

作用:

1.Innodb的MVCC能防止幻读的发生。(不是每个MVCC都可以,看MVCC怎么实现)

2.实现了多个事务并发下,读操作的非阻塞。

场景:MVCC只在REPEATABLE READ和READ COMMITTED两个隔离级别下工作。其他两个隔离级别都和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据。行,而SERIALIZABLE会对所有读取到的行都加锁。

原理:MVCC保存了某一时刻数据的一个快照。意思就是无论事物运行了多久,它们都能看到一致的数据。也就是说在相同的时间下,不同的事物看相同表的数据是不同的。

底层原理:通过在每行记录后面保存两个隐藏的列来实现。这两个列,一个保存了行的创建时间,一个保存了行的过期时间(删除时间)。并且存储的并不是真实的时间值,而是系统版本号(system version number)。每开始一个新的事务,系统版本号都会自动递增。开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。

事务操作:

SELECT

InnoDB会根据以下两个条件检查没行记录:

a. InnoDB只会查找版本早于当前事务版本的数据行(也就是,行的系统版本小于或等于事务的系统版本号),这样可以确保事务读取到的行,要么是事务开始前已经存在的,要么是事务自身插入或者修改过的。

b. 行的删除版本要么未定义,要么大于当前事务的版本号。这样可以确保事务读取到的行,在事务之前未被删除。只有符合上述两个条件的记录,才能被作为返回查询结果.

INSERT

InnoDB为新插入的一行保存当前系统版本号作为行版本号

DELETE

InnoDB为删除的每一行保存当前系统版本号作为删除标识,如果事务a版本号为3且之后执行了删除事务b的版本号为5,那么即使删除了数据,在事务a中还是能查出数据。

UPDATE

UPDATE为插入一行新纪录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为删除标识。

锁:

MySQL InnoDB支持三种行锁定方式:

行锁(Record Lock):锁直接加在索引记录上面,锁住的是key。

间隙锁(Gap Lock):锁定索引记录间隙,确保索引记录的间隙不变。相当于在行间隙的上或下加锁。这样就不能随便加锁。

Next-Key Lock :行锁和间隙锁组合起来就叫Next-Key Lock

默认情况下,InnoDB工作在可重复读隔离级别下,并且会以Next-Key Lock的方式对数据行进行加锁,这样可以有效防止幻读的发生。

扩展锁的知识:

X :写锁:又称排他锁、X锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。

S:读锁:也叫共享锁、S锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S 锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

IX::意向排他锁:表示有加排他锁的意向。

IS::意向共享锁:表示有加共享锁的意向。

顺便提下日志

binlog:

MySQL是多存储引擎的,不管使用那种存储引擎,都会有binlog,而不一定有redo log,简单的说,binlog是MySQL Server层的,redo log是InnoDB层的。

binlog:用于记录用户对数据库更新的SQL语句信息,例如更改数据库表和更改内容的SQL语句都会记录到binlog里,但是对库表等内容的查询不会记录

redo和undo:

redo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作。

1.redo log通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。

2.undo用来回滚行记录到某个版本。undo log一般是逻辑日志,根据每行记录进行记录。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。

MVCC就是利用undo实现的,当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。

总结:1.无非就是通过两个标志位记录版本号,来实现多事务操作下,读的非阻塞(即不会因为同一时刻受到其他事物的增删改的影响,利用undo日志查看到版本号)。2.通过 Next-Key Lock 实现防止幻读的发生。

### MySQLMVCC的定义 MVCC(Multi-Version Concurrency Control),即多版本并发控制,是一种用于提高数据库系统并发性能的技术。通过维护数据的多个版本,MVCC允许读写操作在一定程度上并行执行,而无需加锁,从而减少了事务间的冲突[^1]。 在MySQL的InnoDB存储引擎中,MVCC通过隐藏字段和事务ID来实现数据的多版本管理。这些隐藏字段包括事务创建版本号(DB_TRX_ID)和删除版本号(DB_ROLL_PTR),它们分别记录了数据行被插入或删除时所关联的事务ID[^4]。 --- ### MySQLMVCC的工作原理 #### 1. 数据版本管理 InnoDB通过为每行数据维护两个隐藏字段来支持MVCC: - **DB_TRX_ID**:表示最后一次对该行进行插入或更新的事务ID。 - **DB_ROLL_PTR**:指向该行的回滚段,用于查找该行的历史版本。 当事务对某一行数据进行修改时,InnoDB不会直接覆盖原有数据,而是生成一个新的版本,并将旧版本保存下来。这样,不同事务可以根据自身的隔离级别读取到对应的数据版本[^4]。 #### 2. 读操作 在MVCC机制下,SELECT操作可以不加锁,而是通过读取数据的历史版本来实现一致性读(Consistent Read)。具体来说: - 每个事务在开始时都会被分配一个唯一的事务ID。 - 当事务执行SELECT查询时,会根据当前事务ID和数据行的版本信息(DB_TRX_ID和DB_ROLL_PTR)判断是否能够读取该行数据。 - 如果满足条件,则返回对应版本的数据;否则,继续查找更早的历史版本,直到找到符合要求的版本或无可用版本为止。 #### 3. 写操作 对于INSERT、UPDATE和DELETE等写操作,MVCC通过以下方式处理: - **INSERT**:插入新行时,为其分配最新的事务ID(DB_TRX_ID),并将其作为当前版本。 - **UPDATE**:更新现有行时,生成一个新的版本,并保留旧版本以供其他事务读取。 - **DELETE**:删除行时,标记其为逻辑删除,并记录删除事务ID(DB_ROLL_PTR),以便后续恢复或清理[^4]。 #### 4. 隔离级别的支持 MVCC结合不同的事务隔离级别(如读未提交、读已提交、可重复读和串行化),提供了一致性和并发性的平衡。例如,在可重复读隔离级别下,事务在整个生命周期内看到的数据版本保持一致,避免了不可重复读问题[^5]。 #### 5. 幻读问题的解决 通过间隙锁(Gap Lock)和Next-Key锁,MVCC进一步解决了幻读问题。例如,在事务A对某个范围加共享锁后,其他事务无法在此范围内插入新数据,从而确保查询结果的一致性[^5]。 --- ### 示例代码 以下是一个简单的示例,展示如何在事务中利用MVCC机制: ```sql -- 事务A START TRANSACTION; SELECT * FROM user WHERE id > 5 LOCK IN SHARE MODE; -- 事务B START TRANSACTION; INSERT INTO user(id, user_name, user_code, age, address, hobby) VALUES(6, '赵六', 'TC-00000006', 26, '广西', '羽毛球'); -- 事务B的INSERT操作会被阻塞,直到事务A提交并释放锁 COMMIT; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值