ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

MySQL一致性非锁定读原理以及MVCC简介

2020-06-02 18:09:08  阅读:279  来源: 互联网

标签:事务 快照 版本号 MySQL READ InnoDB MVCC 一致性 SELECT


1、 一致性读


InnoDB 中的一致性读(consistend read)指的是利用多版本查询数据库在某个时间点的快照。此查询可以看到该时间点之前提交的事务所做的更改并且不会被之后的修改或者未提交事务所影响。但是对于同一事务中的较早语句的修改则不适用此规则,这种情况会产生以下异常:如果你更新表中的某些行,一次 SELECT 可能看到更新行的最新版本也可能看到任一行的旧版本;如果其它会话同时更新到同一个表,则可能会看到该表处于数据库中从未存在过的状态。

  • 当事务隔离级别为 REPEATABLE READ 时,同一个事务中的一次性读都说读取该事务第一次查询所建立的快照
  • 当事务隔离级别为 READ COMMITTED 时,同一个事务下的一致性读都会建立和读取此查询自己的最新快照。

一致性读是 InnoDB 在 REPEATABLE READ 和 READ COMMITTED 事务隔离中处理 SELECT 语句的默认模式。一致性读不会在表上设置任何锁,所以其它会话可以对表进行读写操作。

数据库状态的快照适用于事务中的 SELECT 语句,而不一定适用于 DML 语句。如果执行 INSERT 或者 UPDATE某些行然后提交该事务,则从另一个并发 REPEATABLE READ 事务发出的 DELETE 或 UPDATE 语句则会影响那些刚刚提交的数据行。

下面这个示例展示了这种场景:

 1            Session A                              Session B
 2 
 3 
 4            begin;                                   begin;
 5 
 6 -------------------------------------------------------------------------------------
 7 
 8            SELECT * FROM t;                        SELECT * FROM t;
 9 
10            > empty set                             > empty set
11 
12 
13 -------------------------------------------------------------------------------------
14 
15                                                    INSERT INTO t (id) VALUES (1);
16 
17                                                     > 1 row affected
18 
19 
20                                                     SELECT * FROM t;
21 
22                                                     -----------
23 
24                                                     |   id    |
25 
26                                                     -----------
27 
28                                                     |    1    |
29 
30                                                     -----------
31 
32 -------------------------------------------------------------------------------------            
33 
34            SELECT * FROM t;         
35 
36            > empty set
37 
38 -------------------------------------------------------------------------------------                                                    
39 
40                                                     COMMIT;
41 
42 -------------------------------------------------------------------------------------
43 
44            SELECT * FROM t;
45 
46            > empty set
47 
48 -------------------------------------------------------------------------------------
49 
50 
51            DELETE FROM t WAERE id = 1;
52 
53            > 1 row affected
54 
55 -------------------------------------------------------------------------------------
56 
57                                                     SELECT * FROM t;
58 
59                                                     -----------
60 
61                                                     |   id    |
62 
63                                                     -----------
64 
65                                                     |    1    |
66 
67                                                     -----------
68 
69 -------------------------------------------------------------------------------------
70 
71            COMMIT;
72 
73 -------------------------------------------------------------------------------------
74 
75                                                     SELECT * FROM t;
76 
77                                                     > empty set
78 
79 -------------------------------------------------------------------------------------
80 
81            SELECT * FROM t;
82 
83            -----------
84 
85            |   id    |
86 
87            -----------
88 
89            |    1    |
90 
91            -----------
92 
93 -------------------------------------------------------------------------------------

一致的读取不适用于某些 DDL语句,如:

1) 一致性读不适用于 DROP TABLE ,因为表已经被 InnoDB 销毁了。

2) 一致性读不适用于 ALTER TABLE ,因为 ALTER TABLE 实际是生成一张原始表的临时表,并在构建完成后删除原始表。 在事务中进行一致的读取时,新表中的行不可见,这种情况下事务会返回 ERTABLEDEF_CHANGED 错误(表定义已更改,请重试事务)。

在没有指定 FOR UPDATE 或者 LOCK IN SHARE MODE 的情况下 INSERT INTO ... SELECT ,UPDATE ...(SELECT)和 CREATE TABLE... 等语句中的的读取会有以下差异:

  • 默认情况下,就像 READ COMMITTED 一样,即使在同一事务中,每个一致性读都会建立和读取自己的快照。
  • 如果将 innodblocksunsafe forbinlog 设置为了 enable 并且事务隔离级别不是 SERIALIZABLE,则读操作不会再行上加锁。

2、多版本并发控制


 

上面说的一致性读(consistend read)的主要是基于MVCC实现,而 MySQL 中大多数事务型(如:InnoDB、Falcon 等)存储引擎都同时实现了 MVCC(Multi-Version Concurrency Control) 

当前不仅仅是 MySQL,其它数据库系统(如:Oracle、PostgreSQL)也都实现了 MVCC。值得注意的是 MVCC 并没有一个统一的实现标准,所以不同的数据库,不同的存储引擎的实现都不尽相同。

多版本控制的核心是数据快照,而 InnoDB 则是通过 undo log 来存储数据快照。

下面展示了在不考虑 redo log 的情况下利用 undo log工作的简化过程:

序号    动作
1    开始事务
2    记录数据行数据快照到undo log
3    更新数据
4    将undo log写到磁盘
5    将数据写到磁盘
6    提交事务

1)为了保证数据的持久性数据要在事务提交之前持久化。 2)undo log的持久化必须在在数据持久化之前,这样才能保证系统崩溃时,可以用undo log来回滚事务。

 

2.1、Innodb中的隐藏列

InnoDB 通过 undo log 保存了已更改行的旧版本的信息的快照。InnoDB 的内部实现中为每一行数据增加了三个隐藏列用于实现 MVCC 。

列名        长度(字节)          作用
DBTRXID      6          插入或更新行的最后一个事务的事务标识符。(删除视为更新,将其标记为已删除)
DBROLLPTR    7         写入回滚段的撤消日志记录(若行已更新,则撤消日志记录包含在更新行之前重建行内容所需的信息)
DBROWID      6         行标识(隐藏单调自增id)

MVCC 只在 READ COMMITED 和 REPEATABLE READ 两个隔离级别下工作。READ UNCOMMITTED 总是读取最新的数据行,而不是符合当前事务版本的数据行。而 SERIALIZABLE 则会对所有读取的行都加锁。

 

2.2 每个操作所做的内容

SELECT

InnoDB 会根据两个条件来检查每行记录:

1) InnoDB 只查找版本(DBTRXID)早于当前事务版本的数据行(行的系统版本号 <= 事务的系统版本号,这样可以确保数据行要么是在开始之前已经存在了,要么是事务自身插入或修改过的)。

2) 行的删除版本号(DBROLLPTR)要么未定义(未更新过),要么大于当前事务版本号(在当前事务开始之后更新的)。这样可以确保事务读取到的行,在事务开始之前未被删除。

INSERT

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

DELETE

InnoDB 为删除的每一行保存当前的系统版本号作为行删除标识。

UPDATE

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

 

 

参考链接:https://juejin.im/entry/5af2597bf265da0b7e0c3e5f

标签:事务,快照,版本号,MySQL,READ,InnoDB,MVCC,一致性,SELECT
来源: https://www.cnblogs.com/musl/p/13032717.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有