什么是MVCC?
使用READ COMMITTD、REPEATABLE READ 这两种隔离级别的事务执行select操作时,我们通过记录的版本链来控制事务访问相同记录时的行为,这种机制称为多版本并发控制(Multi-Version Concurrency Control).
目的:是为了提升并发访问的性能。
并发的事务在运行过程中会出现一些可能引发一致性问题的现象
-
脏写(dirty write):一个事务修改了另一个事务未提交的数据;
-
脏读(dirty read):一个事务读到了另一个未提交事务修改的数据;
-
不可重复度(non-repeatable read):一个事务修改了另一个未提交事务的读取的数据;
-
幻读(phantom):一个事务查询到数据,在未执行完之前,另一个事务又写入了一些能查询到的数据。
四种隔离级别如下:
-
READ UNCOMMITTED :读未提交,可能发生脏读、不可重复读和幻读;
-
READ COMMITTED :读已提交
-
REPEATABLE READ: 可重复读 (默认的隔离级别)
-
SERIALIZABLE :可串行化
隔离级别的出现也是为了换取性能的提升,隔离级别越低,性能越高,越有可能发生问题。
修改隔离级别:
#sql语法
set global/session transaction isolation leavel 隔离级别;
global 表示全局范围
session:表示只是在当前会话中起作用
# 启动参数
--transaction-isolation=隔离级别
版本链
我们看下undo日志的格式和对应的版本链
在mysql的update和delete过程中,每对记录进行一次改动,都会记录一条undo日志,每条日志的roll_pointer都会记录innodb中最新的值,因此之前所有的改动都可以通过此属性串联。
版本链有了,但哪些版本对当前的事务可见?我们通过ReadView来控制。
ReadView
在ReadView中一共有4个比较重要的内容:
-
m_ids:生成ReadView时,当前系统中活跃的读写事务的事务id列表;
-
min_trx_id: 生成ReadView时,m_ids中最小的id值;
-
max_trx_id: 生成ReadView时,应用要分配给下一个事务的事务id;
-
creator_trx_id: 生成ReadView时,改事务的事务id;大家注意几点:
-
所有的属性值都是在生成ReadView时确认,也就是说ReadView是按事务隔离的;
-
max_trx_id 为下一个事务id,因为并行时,最后一个事务id可能会先提交
此时我们再关联版本链来看下如何访问。
-
a,被访问版本的trx_id的值与ReadView中的creator_trx_id相同,表示在同一个事务中,所以这个版本可以被当前事务访问;
-
b,如果被访问版本的trx_id的值小于ReadView中的min_trx_id,表示该事务在生成ReadView前已提交,这个版本可以被访问;
-
c,如果被访问版本的trx_id大于或等于ReadView中max_trx_id,表示生成该版本的事务在生成ReadView后才生成,这个版本不可被当前事务访问;
-
d,如果被访问版本的trx_id在min_trx_id和max_trx_id之间,如果m_ids中,表示还在活跃,则不能被访问,如果不在,说明已提交,可访问。
read committed 每次读取数据前都会生成一个ReadView,这样如果一个事务中多次读取,新提交的数据也可以被读取到;repeatable read 只在第一次读取时生成一个ReadView,因为会根据上面的c和d逻辑判断,所以,新提交的数据是无法读取的。
文章评论