美文网首页
1.3 REPEATABLE READ(可重复读)

1.3 REPEATABLE READ(可重复读)

作者: 元代码 | 来源:发表于2017-08-22 16:45 被阅读0次

    1.设置为可重复读

    SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

    2.首先TB做出一次查询,此时name为bb

    3.TA对数据进行修改,并提交

    4.此时加入session C作为对比,使用自动事务并做出查询,可见数据已经被修改

    5.在已经开启事务的TB中,查询到的,仍然是数据开启事务之前的状态,所以数据是可重复读的

    可重复读隔离级别中,每当事务开始后,第一次执行sql语句时(或者执行START TRANSACTION WITH CONSISTENT SNAPSHOT)MVCC会建立一个read view,选取当时的系统版本号,作为事务版本号,以Undo log的行系统版本号与事务版本号进行对比,增删改查都要遵循如下模式:

    SELECT:

    1, InnoDB只查找版本早于当前事务版本的数据行(行的系统版本号小于等于事务版本号),这样可以确保事务读取的行,要么是事务开始前就存在的,要么是事务自身插入的或修改过的。

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

    INSERT:

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

    DELETE:

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

    UPDATE:

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

    所以READ COMMITTED和REPEATABLE READ的区别在于,READ COMMITTED总是读取被锁定行的最新一份快照数据, 所以会有不可重复读的问题。而REPEATABLE READ读取事务开始时行系统版本号小于事务版本号的数据,解决不可重复读的问题。

    此外要提的一点是,MySql的REPEATABLE READ与Oracle的不同,不但解决了不可重复读问题,还解决的“幻读”问题。

    幻读的产生:遵循上述增删改查模式,假设TA事务的事物版本号为3,TB早于TA开启事务,TB事物版本号为2,TB先新增一条数据,行数据的版本号为2,并提交。TB提交后,TA查询时,满足“行的系统版本号小于等于事务版本号”的条件,可以查到数据,形成“幻读”。

    InnoDB采用Next-key Lock(间隙锁)来避免“幻读”问题。

    Record Lock:单个行记录的锁,锁定的是索引而非记录本身。

    GAP Lock:间隙锁,锁定一个范围,但不包含记录本身。

    Next-Key Lock:Gap Lock+Record Lock 锁定一个范围并锁定记录本身。

    举例说明:

    某表字段为ID和NAME,有3条睡觉,ID分别为10,20,50。

    如果索引为 10,20,50,那么:

    Record Lock:select * from tab where id = 10 for update; //对id=10单行进行加锁

    Gap Lock锁范围:(-∞,10)(10,20)(20,50)(50,+∞)

    Next-Key Lock锁范围:(-∞,10] (10,20] (20,50] (50,+∞)

    当查询的索引含有唯一属性时,InnoDB会对Next-Key Lock进行优化,将其降级为Record Lock,即仅锁住索引本身,而不是范围。

    虽然避免了幻读问题,但是还有个特殊情况,感觉可以叫做“幻改”,即当前事务修改了本身并不能查询到的数据。这也是MVCC造成的假象,当前事务虽然查询不到其他事务提交的数据,但是可以对其他事务提交的数据进行修改。

    相关文章

      网友评论

          本文标题:1.3 REPEATABLE READ(可重复读)

          本文链接:https://www.haomeiwen.com/subject/fjmldxtx.html