mysql的MVCC多版本并发机制

发布时间 2023-06-21 15:06:26作者: 数据库小白(专注)

1. mysql的MVCC多版本并发机制

1.1. 定义

  • MVCC
    MVCC,全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。
    在MySQL中,MVCC并不是Server级别的实现,而是InnoDB引擎的实现。

  • 快照读
    像不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;由于是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。

  • 当前读
    像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

  • 幻读
    事务A 按照一定条件进行数据读取, 期间事务B 插入了相同搜索条件的新数据,事务A再次按照原先条件进行读取时,发现了事务B 新插入的数据,这种情况称为幻读。
    注意:幻读特指新插入的数据。如果事务A 按一定条件搜索, 期间事务B 删除了符合条件的某一条数据,导致事务A再次读取时数据少了一条。这种情况归为不可重复读。

1.2. 什么情况下会出现幻读?

  • 全部使用快照读
    这种情况是最简单的。由于MVCC机制的存在,每个事务开始的时候读取的都是固定的版本的数据。很明显这种情况是不会出现幻读的。

  • 全部使用当前读
    由于MySQL间隙锁读存在,后执行的事务会被之前运行的事务阻塞。即退化到串形执行。这种情况也不会存在幻读情况

  • 当前读快照读混用
    可以发现这种混用的情况是会出现幻读的。

1.3. 结论

可重复读隔离级别下,一个事务中只使用当前读,或者只使用快照读都能避免幻读。如果当前读和快照读混用的话就不能保证不出现幻读。

1.4. 事务的ACID

原子性:整个事务中的所有操作要么全部提交成功,要么全部失败回滚;
一致性:总是从一个一致性的状态转换到另外一个一致性的状态,无中间状态;
隔离性:一个事务所做的修改在最终提交以前,对其他事务是不可见的;
持久性:一旦事务提交,其所做的修改就会永久保存到数据库中,即使系统崩溃,数据也不会丢失。

事务的隔离级别

未提交读:事务中的修改,即是没有提交,对其他事务也都是可见的,会出现脏读;
提交读:一个事务开始时,只能看见已经提交的事务所做的修改,也叫不可重复读;
可重复读:保证了再同一个事务中多次读取同样记录的结果是一致的,会出现幻读;
可串行化:会在读取的每一行数据上都加锁,可能导致大量的超时和锁竞争问题。

mvcc

1.5. 锁

写锁比读锁有更高的优先级,因此一个写锁请求可能会被插入到读锁队列的前面。

共享锁(读锁):多个客户在同一时刻可以同时读取同一个资源,二互不干扰;
排他锁(写锁):一个写锁会阻塞其他的写锁和读锁。

1.6. 锁粒度

尽量只锁定需要修改的部分数据,而不是所有资源,锁定的数据量越少,则系统的并发程度越高。
表锁:它会锁定整张表,一个用户对表进行写操作(插入、删除、更新等)前,需要先获得写锁,这会阻塞其他用户对该表的所有读写操作。只有没有写锁时,其他读取的用户才能获得读锁,读锁之前是不相互阻塞的;
行级锁:最大程度支持并发处理,只在存储引擎层面实现,而MySQL服务器层没有实现。

1.7. 多版本并发控制(MVCC)

不管需要执行多长时间,每个事务看到的数据都是一致的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。

InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现。这两个列,一个保存了行的创建时间,一个保存行的删除时间,并不是实际的世界,而是系统版本号。每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号作比较,MVCC只在可重读读和提交读两种隔离级别下工作。

可重复读下的MVCC的操作方法