0%

MySql——隔离级别

  • 当有多个事务同时执行时,就可能出现下面几种情况:

    1. 脏读:对于两个事务T1与T2,T1读取了已经被T2更新但是还没有提交的字段之后,若此时T2回滚,T1读取的内容就是临时并且无效的
    2. 不可重复读:对于两个事务T1和T2,T1读取了一个字段,然后T2更新了该字段并提交之后,T1再次提取同一个字段,值便不相等了。
    3. 幻读:对于两个事务T1、T2,T1从表中读取数据,然后T2进行了INSERT操作并提交,当T1’再次读取的时候,结果不一致的情况发生。
  • 解决这些问题的方法:

    1. 读未提交:表示一个事务还没有提交时,它做的变更是可以被其他事务看到。
    2. 读提交:表示一个事务只有在提交后,它做的表更才可以被其他事务看到。
    3. 可重复读:一个事务执行过程中看到的数据,总是跟这个事务启动时看到的数据是一致的。
    4. 串行化:写数据会加写锁,读会加读锁。当出现读写锁冲突时,后访问的事务必须等前一个事务执行完成后才可以执行。
  • 读提交和可重复读的实现就需要借助视图(read view),视图中存储着事务需要使用数据版本,视图和数据版本的关系如下:对于一个事务视图来说,除了自己的更新总是对自己可见外,对其他的事务:

    1. 数据版本未提交,不可见
    2. 数据版本已提交,但是是在视图创建后提交的,不可见
    3. 数据版本已提交,而且是在视图创建前提交的,可见
  • 可重复读会在事务开启时创建一个视图,之后读数据时会在这个视图中取数据,而在整个事务的过程中视图里面的数据版本是不会改变的,所以可重复读就可以保证在一个事务里读到的数据是一致的,这个叫做一致性读。

  • 而读提交会在每一行Sql语句开始执行的时候创建视图,当其他事务在Sql语句执行前提交了事务版本,那该事务提交的版本对原本事务来说是可见的。

  • 其实begin/start transaction命令并不是一个事务的起点,只有当执行它们后的第一个操作语句的时候,事务才会真正地启动。想要马上启动事务的语句start transaction with consistent snapshot

  • 设置事务的隔离级别语句是:set session transaction isolation level [隔离级别](read uncommitted|read committed|repeatable read|serializable)

  • 默认提交语句autocommit=1

  • 其实在MySql里有两种视图地概念:

    1. 一个是“view”,普通的视图,创建视图的语法create view...
    2. 一个是“read view”,是InnoDB在实现MVCC(多版本并发控制)时用到地一致性读视图,用于支持RC和RR的实现。

快照或数据版本在MVCC中是怎么工作的?

  • InnoDB里每一个事务都有一个唯一的事务ID,叫作transaction id。它是在事务开始的时候向InnoDB的事务系统申请的,并按照申请的顺序严格递增。
  • 每行数据都是有多个版本的。每次事务更新数据时,都会生成一个新的数据版本,并把transaction id赋给这个数据版本的事务ID,叫做row trx_id。

img

  • 其实V1、V2、V3这三个数据版本并不是物理上真实存在的,二十每次需要的时候根据当前版本和undo log计算出来的。图中的虚线代表了undo log(回滚日志)。
  • 而在实现数据的可见性的时候,InnoDB会为每个事务构造一个数组,用来保存这个事务启动的瞬间,当前启动了但还没有提交的事务ID,数组里事务ID的最小值记为低水位,而ID的最大值记为高水位。而视图数组和高水位就组成了当前事务的一致性视图。

img

  • 这样对于当前事务的启动瞬间来说,一个数据版本的 trx_id,就有以下几种可能:

    1. 如果落在绿色部分,表示这个版本是已经提交的事务或当前事务自己生成的,这个数据是可见的

    2. 如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的

    3. 如果落在黄色部分,有两种情况:

      a. 若这个trx_id在这个黄色区域,表示这个版本由还没有提交地事务生成,不可见。

      b. 若这个trx_id不在这个黄色区域,表示这个版本是已经提交了的事务生成的,可见。

-------------本文结束感谢您的阅读-------------