大家好,我是热心的大肚皮,皮哥。
事务的隔离级别
可串型化执行
对一个服务器来说,可以有多个客户端连接,而且每一个事务都对应一次数据状态的变换,为了保证事务的ACID4大特性,如果单纯的串行的执行事务,则会降低系统吞吐量与资源利用率,所以mysql选择了可串型化执行,舍弃了一部分隔离性来换取一部分性能,也就是某个事务操作某个数据时,其他试图操作相同的数据的事务需要等待,当事务提交时,其他操作相同的数据的事务才可能进行操作,不操作相同的数据则并行操作。
事务并发执行遇到的一致性问题
严重性是,脏写>脏读>不可重复读>幻读。
SQL标准中的4种隔离级别
MVCC-多版本并发控制
版本链
每次记录的改动都会生成一个undo日志,每个undo日志都有一个roll_pointer,通过这些roll_pointer组成一个链表,也就是版本链。
insert into hero values(1,'刘备', '蜀');
update hero set name='关羽' where number =1;
update hero set name='张飞' where number =1;
update hero set name='赵云' where number =1;
update hero set name='马超' where number =1;
对应的版本链如下。
ReadView
ReadView一致性视图主要作用是判断版本链中哪个版本的事务是当前事务可见的,主要包含4个比较重要的内容。
ReadView的使用
具体使用方式如下。
那么上面说的4种隔离级别何时生成的呢?
# Transaction 100
BEGIN;
update hero set name='关羽' where number =1;
update hero set name='张飞' where number =1;
# Transaction 200
BEGIN;
#修改了一些别的表记录
表中number为1的记录对应的版本链如下。
假设现在有个新事务开始执行。
BEGIN;
#select1: transaction 100、200未提交
select * from hero where number=1;#得到的列name为'刘备'
具体过程如下。
步骤1 在执行select语句时先生成一个ReadView。这时候ReadView中的m_ids的列表内容就是[100,200],min_trx_id为100,max_trx_id为201,creator_trx_id为0。
步骤2 然后从版本链中挑可见的数据。最新的name为张飞,但是这个版本的trx_id为100,在m_ids列表内,不符合要求。根据roll_pointer跳到下一个版本。
步骤3 下一个关羽原因同上,继续跳到下一个版本。
步骤4 下一个为刘备,trx_id为80,小于ReadView中的min_trx_id值100。符合要求,返回数据。
二级索引与MVCC
具体使用方式如下。只有聚簇索引才有trx_id和roll_pointer,那么使用二级索引执行查询如何判断呢?分为两个步骤。
步骤1 二级索引页面的Page Header有个PAGE_MAX_TRX_ID的属性,每次对该页面进行增删改操作时,如果操作的事务id大于PAGE_MAX_TRX_ID,则将PAGE_MAX_TRX_ID设置为当前事务id,在查询时,根据min_trx_id与PAGE_MAX_TRX_ID进行比较,如果大于则可见,否则执行步骤2。
步骤2 利用二级索引的主键进行回表,接下来的过程就是聚簇索引的多版本并发控制过程了。