MySQL中的MVCC机制主要在以下情况下起作用:
-
使用支持MVCC的存储引擎:MVCC主要是MySQL的InnoDB存储引擎中实现并发控制的一种方式,只有当使用InnoDB作为表的存储引擎时,MVCC机制才会生效。
-
非串行化事务隔离级别:MVCC在“读已提交(Read Committed)”和“可重复读(Repeatable Read)”这两种事务隔离级别下发挥作用。在“读未提交(Read Uncommitted)”隔离级别下,虽然也可能看到不同事务版本的数据,但这并非严格意义上的MVCC;而在“串行化(Serializable)”隔离级别下,为了保证事务之间的完全隔离,通常会放弃MVCC机制而采用更严格的锁策略。
-
读已提交(Read Committed):每个查询语句执行前都会获取最新的数据快照,因此同一个事务内前后两次相同的查询可能返回不同的结果。
-
可重复读(Repeatable Read):这是MySQL的默认事务隔离级别,在这个级别下,事务开始时会获取一个数据快照,并在整个事务期间都基于该快照进行读取操作,这样可以确保事务内的多次相同查询始终得到一致的结果。
-
-
非锁定读操作:MVCC主要针对的是不加锁的SELECT查询,即所谓的“快照读”。对于“当前读”操作,如
SELECT ... FOR UPDATE
、SELECT ... LOCK IN SHARE MODE
以及INSERT、UPDATE、DELETE等写操作,通常不会通过MVCC来提供数据的一致性视图,而是直接应用行级锁或者间隙锁来避免并发问题。
在多个事务共同操作相同数据行时,MVCC(多版本并发控制)机制能够确保事务间的并发访问不会相互阻塞,同时保持事务的隔离性。以下是一个简化的描述:
假设我们有两个事务A和B,它们都在操作同一行数据row1
。
事务A的操作流程:
- 事务A开始并获取一个事务ID(Transaction ID, trx_id)。
- 事务A执行查询操作读取
row1
的数据。InnoDB存储引擎会根据事务A的视图(即当前已提交事务的快照)查找row1
对应的时间戳或事务ID来决定哪些版本的数据对事务A可见。 - 如果事务A需要更新
row1
,它并不直接覆盖原有数据,而是创建一个新的数据版本,并将这个版本标记为属于事务A的未提交状态。同时,旧版本的数据并不会立即删除,而是保留下来以供其他事务可能需要查看的历史版本。 - 在事务A提交前,所有对
row1
的更改只对事务A自身可见;其他事务在此期间读取row1
时,看到的是事务A开始之前已经提交的版本。
事务B的操作流程:
- 同样,事务B开始并获取自己的事务ID。
- 当事务B尝试读取
row1
时,它也会基于自己的事务视图去寻找合适的数据版本。 - 如果事务B是在事务A提交之后开始读取
row1
,那么它将会看到事务A的最新提交版本(如果事务A已经提交了对row1
的更改)。 - 如果事务B尝试修改
row1
,即使在事务A还未提交的情况下,由于MVCC的存在,它同样可以进行无冲突的修改,生成新的版本。
通过这种方式,两个事务可以在不互相等待对方释放锁的情况下,独立地进行读写操作。当事务提交后,系统会清理不再需要的旧版本记录,以保证空间的有效利用。
总的来说,在MVCC中,每个事务都像是在操作自己特定版本的数据集,从而避免了传统锁定机制带来的潜在阻塞问题,提高了数据库系统的并发性能。