欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

innodb隔离级别原理实现

程序员文章站 2022-05-10 13:09:23
...
mysql数据库文件
InnoDB 和 MyISAM的区别
Innodb隔离级别原理实现
InnoDB主备复制

一、MVCC

innodb隔离级别原理实现
            
    
    博客分类: mysql 隔离级别isolationmvccinnodb原理 

    InnoDB是一个多版本存储引擎:它保存关于已更改行的旧版本的信息,以支持诸如并发和回滚之类的事务特性.可以认为MVCC是行级锁的一个变种,但它在很多情况下避免了加锁操作,因此开销更低。

innodb隔离级别原理实现
            
    
    博客分类: mysql 隔离级别isolationmvccinnodb原理 


    innodb会为每一行添加三个字段:
  • 6-byte ID字段:隐含主键ID。
  • 6-byte DB_TRX_ID字段:记录创建时事务的版本,这个版本号随着事务的创建不断递增。
  • 7-byte DB_ROLL_PTR字段:记录了指向undo日志记录的指针。undo日志用于事物回滚。
    MCVV只在REPEATABLE READ和READ COMMITTED两个隔离级别下工作。

二、事务链表

    MySQL中的事务在开始到提交这段过程中,都会被保存到一个叫trx_sys的事务链表中,这是一个基本的链表结构:

innodb隔离级别原理实现
            
    
    博客分类: mysql 隔离级别isolationmvccinnodb原理 


    新建事务(当前事务)与commit 的事务不在活跃事务链表中。

三、undo log

innodb隔离级别原理实现
            
    
    博客分类: mysql 隔离级别isolationmvccinnodb原理 

    当事务1更改该行的值时,会进行如下操作:
  • 用排他锁锁定该行
  • 记录redo log
  • 把该行修改前的值Copy到undo log,即上图中下面的行
  • 修改当前行的值,填写事务编号,使回滚指针指向undo log中的修改前的行


四、ReadView

    有了前面隐藏列和事务链表的基础,接下去就可以构造MySQL实现MVCC的关键——ReadView。
    ReadView说白了就是一个数据结构,在事务开始的时候被创建。这个数据结构中包含了3个主要的成员:ReadView{low_trx_id, up_trx_id, trx_ids},在并发情况下,一个事务在启动时,trx_sys链表中存在部分还未提交的事务,那么哪些改变对当前事务是可见的,哪些又是不可见的,这个需要通过ReadView来进行判定,首先来看下ReadView中的3个成员各自代表的意思:
  • low_trx_id表示该事务启动时,当前事务链表中最大的事务id编号,也就是最近创建的除自身以外最大事务编号;
  • up_trx_id表示该事务启动时,当前事务链表中最小的事务id编号,也就是当前系统中创建最早但还未提交的事务;
  • trx_ids表示所有事务链表中事务的id集合。

    上述3个成员组成了ReadView中的主要部分,简单图示如下:

innodb隔离级别原理实现
            
    
    博客分类: mysql 隔离级别isolationmvccinnodb原理 


    InnoDB默认的隔离级别为Repeatable Read (RR),可重复读。InnoDB在开始一个RR读之前,会创建一个全局Read View。Read Commited (RC)在每次语句执行的过程中,重新在row_search_for_mysql函数中创建当前的一份read_view。Read View用于判断一条记录的可见性。Read View定义在read0read.h文件中。
具体的算法如下:

  1. 设该行的当前事务id为trx_id,read view中最早的事务id为up_trx_id, 最迟的事务id为low_trx_id。
  2. 如果trx_id< up_trx_id的话,那么表明该行记录所在的事务已经在本次新事务创建之前就提交了,所以该行记录的当前值是可见的。跳到步骤6。
  3. 如果trx_id>low_trx_id的话,那么表明该行记录所在的事务在本次新事务创建之后才开启,所以该行记录的当前值不可见,跳到步骤5。否则该行记录的当前值是可见的,跳到步骤6。
  4. 如果up_trx_id<=trx_id<=low_trx_id, 那么表明该行记录所在事务在本次新事务创建的时候处于活动状态,从up_trx_id到low_trx_id进行遍历,如果trx_id等于他们之中的某个事务id的话,那么不可见。跳到步骤5。
  5. 从该行记录的DB_ROLL_PTR指针所指向的回滚段中取出最新的undo-log的版本号,将它赋值该trx_id,然后跳到步骤2。
  6. 将该可见行的值返回。



五、事务隔离级别
  
    REPEATABLE READ(默认隔离级别)
    select:开始一个RR读之前,会创建一个全局Read View。会出现幻读
CREATE TABLE t (a INT NOT NULL, b INT) ENGINE = InnoDB;
INSERT INTO t VALUES (1,2),(2,3),(3,2),(4,3),(5,2);
UPDATE t SET b = 5 WHERE b = 3;

b字段是索引:只会锁住b=3的记录
b字段不是索引:会锁住全表记录

x-lock(1,2); retain x-lock
x-lock(2,3); update(2,3) to (2,5); retain x-lock
x-lock(3,2); retain x-lock
x-lock(4,3); update(4,3) to (4,5); retain x-lock
x-lock(5,2); retain x-lock


    READ COMMITTED
    select:每次语句执行的过程中,重新在row_search_for_mysql函数中创建当前的一份read_view。不可重复读
b字段是索引:只会锁住b=3的记录
b字段不是索引:会先锁住全表记录,然后释放b!=3的记录的锁

x-lock(1,2); unlock(1,2)
x-lock(2,3); update(2,3) to (2,5); retain x-lock
x-lock(3,2); unlock(3,2)
x-lock(4,3); update(4,3) to (4,5); retain x-lock
x-lock(5,2); unlock(5,2)


    READ UNCOMMITTED
    select:返回最新记录。脏读

    SERIALIZABLE
    select:InnoDB隐式地将所有普通SELECT语句转换为SELECT ... LOCK IN SHARE MODE。并且通过间隙锁(next-key locking)策略防止幻读的出现。

  • innodb隔离级别原理实现
            
    
    博客分类: mysql 隔离级别isolationmvccinnodb原理 
  • 大小: 9.3 KB
  • innodb隔离级别原理实现
            
    
    博客分类: mysql 隔离级别isolationmvccinnodb原理 
  • 大小: 15 KB
  • innodb隔离级别原理实现
            
    
    博客分类: mysql 隔离级别isolationmvccinnodb原理 
  • 大小: 26 KB
  • innodb隔离级别原理实现
            
    
    博客分类: mysql 隔离级别isolationmvccinnodb原理 
  • 大小: 19.5 KB
  • innodb隔离级别原理实现
            
    
    博客分类: mysql 隔离级别isolationmvccinnodb原理 
  • 大小: 42.1 KB