-
MVCC全称为Multi-Version Concurrency Control,即多版本并发控制。它是一种数据库管理系统中的并发控制机制,用于控制多个用户同时对同一数据进行读写的情况。
总结:MVCC就是为了实现读-写冲突不加锁,而这个读指的就是快照读, 而非当前读,当前读实际上是一种加锁的操作,是悲观锁的实现
MVCC的实现方式是,在数据库中保存多个版本的数据,每个版本都有一个时间戳,代表该版本的创建时间。当一个用户请求读取数据时,系统会根据时间戳选择最新的版本进行读取,而不会读取其他用户正在修改的版本。当用户请求修改数据时,系统会创建一个新的版本,并将该用户的时间戳作为该版本的创建时间戳。这样,不同用户之间的读写操作都不会互相干扰,从而实现了并发控制。
-
在 MySQL 中,InnoDB 是默认的存储引擎,并且默认的隔离级别是可重复读(REPEATABLE READ)。在可重复读隔离级别下,InnoDB 使用 MVCC(多版本并发控制)来处理并发读写操作。
-
一般情况下innodb模式是支持行锁的,表锁的开销通常比行锁要小。这是因为表锁只需要获取一把锁来锁定整个表,而行锁需要获取每一行的锁。因此,行级锁在并发较高的情况下可能会产生更多的锁冲突,从而导致性能下降。**通常情况下只有在使用特定的如当对表进行ALTER TABLE操作时才会使用到表锁,或者在如果某个事务持有锁的时间过长,其他事务需要等待该事务完成才能获取锁,这可能导致其他事务长时间等待,进而造成锁表。**如果表上的索引设计不合理,或者查询条件不恰当,可能导致MySQL在执行查询时需要锁定更多的行,从而增加锁表的可能性。
-
尽管 InnoDB 使用了 MVCC,但仍然可能出现幻读的情况。幻读是指在同一个事务中,对于相同的查询条件,第二次查询返回了不同的结果行数或数据行。MVCC 主要解决的是读取已有数据时的一致性问题,而对于插入新数据导致的幻读问题,MVCC 并不能完全解决。
要避免幻读,可以使用以下方法:
- 使用锁定读(Locking Read):通过使用
SELECT ... FOR UPDATE
或SELECT ... LOCK IN SHARE MODE
语句,可以在读取数据的同时锁定所选行或范围,阻止其他事务对相同数据进行修改。这样可以确保在同一个事务中对相同的查询条件进行多次查询时,数据保持一致,其实就是把快照度改为了当前读。 - 使用序列化隔离级别(SERIALIZABLE):将事务隔离级别提升到最高级别,即串行化,可以完全避免幻读问题。但需要注意的是,这可能会对并发性能产生较大的影响,因为它会限制并发操作。
- 使用锁定读(Locking Read):通过使用
扩展:RC(读提交),RR(可重复度)级别下的InnoDB快照读有什么不同?
正是Read View生成时机的不同,从而造成RC,RR级别下快照读的结果的不同
- 在RR级别下的某个事务的对某条记录的第一次快照读会创建一个快照及Read View, 将当前系统活跃的其他事务记录起来,此后在调用快照读的时候,还是使用的是同一个Read View,所以只要当前事务在其他事务提交更新之前使用过快照读,那么之后的快照读使用的都是同一个Read View,所以对之后的修改不可见;
- 即RR级别下,快照读生成Read View时,Read View会记录此时所有其他活动事务的快照,这些事务的修改对于当前事务都是不可见的。而早于Read View创建的事务所做的修改均是可见
- 而在RC级别下的,事务中,每次快照读都会新生成一个快照和Read View, 这就是我们在RC级别下的事务中可以看到别的事务提交的更新的原因
总之在RC隔离级别下,是每个快照读都会生成并获取最新的Read View;而在RR隔离级别下,则是同一个事务中的第一个快照读才会创建Read View, 之后的快照读获取的都是同一个Read View。