zoukankan      html  css  js  c++  java
  • RR隔离级别下通过next-key locks 避免幻影读

    ---恢复内容开始---

    mysql innodb目前使用范围最广的两种隔离级别为RC和RR,RR修复了RC中所存在的不可重复读

    READ COMMITED

    不可重复读

    在同一事务中两次查看的结果集不同,如下session1的查看结果集受session2提交的事物影响

    05:47:35[test](;)> select @@tx_isolation;
    +----------------+
    | @@tx_isolation |
    +----------------+
    | READ-COMMITTED |
    +----------------+

    session1
    03:28:11[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 03:28:21[test](;)> select * from t1; Empty set (0.01 sec) session2 03:28:27[test](;)> insert into t1 values(1,1,1,1,1); Query OK, 1 row affected (0.00 sec) 03:29:25[test](;)> select * from t1; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 1 | 1 | 1 | 1 | 1 | +----+------+------+------+------+ 1 row in set (0.00 sec)

    幻影读(Phantom Rows)

    什么是幻影读

    同一事务保证了一致性读后,查询时对提交的事务是不可见的,但是变更的时候是可见的,所以就有可能引发幻影读

    为什么会导致幻影读

    对于update或delete操作(可以使用SELECT with FOR UPDATE or LOCK IN SHARE MODE来进行模拟),innodb只加记录锁(满足条件索引记录)而不是gap锁,gap锁只用于外键约束和duplicate key的检查,所以允许另一事务在锁定的记录旁边自由插入新记录

    如col2上有索引,在满足col2>5的条件索引上加索引(对于RC,只在col2为10的索引记录上加X lock),所以在另一会话总插入col2 为非10的记录则会成功

    set tx_isolation='read-committed' ;                                                                                  
    session 1                                                                                                            
    07:46:16[test](;)> begin;                                                                                            
    Query OK, 0 rows affected (0.00 sec)                                                                                 
                                                                                                                         
    07:46:20[test](;)> select * from t1 where col2>5 for update;                                                         
    +----+------+------+------+------+                                                                                   
    | id | col1 | col2 | col3 | col4 |                                                                                   
    +----+------+------+------+------+                                                                                   
    |  2 |    2 |   10 |    2 |    2 |                                                                                   
    +----+------+------+------+------+                                                                                   
    1 row in set (0.00 sec)                                                                                              
                                                                   07:44:48[test](;)> begin;                             
                                                                   Query OK, 0 rows affected (0.00 sec)                  
                                                                                                                         
                                                                   07:46:36[test](;)> insert into t1 values(3,3,6,3,3);  
                                                                   Query OK, 1 row affected (0.00 sec)                   
                                                                                                                         
                                                                   07:46:38[test](;)> commit;                            
                                                                   Query OK, 0 rows affected (0.10 sec)                  
    07:46:31[test](;)> select * from t1 where col2>5;                                                                    
    +----+------+------+------+------+                                                                                   
    | id | col1 | col2 | col3 | col4 |                                                                                   
    +----+------+------+------+------+                                                                                   
    |  3 |    3 |    6 |    3 |    3 |                                                                                   
    |  2 |    2 |   10 |    2 |    2 |                                                                                   
    +----+------+------+------+------+                                                                                   
    2 rows in set (0.00 sec)                                                                                             

    若col2上无索引,也会是同样的结果现象,如果条件字段上无索引,innodb会先将所有行都加上锁,然后返回给server层根据条件筛选,满足条件则释放行锁,不满足条件则不释放

    REPEATABLE READ

    如何实现可重复读

    事物开始时记录当前的快照版本,事务期间读取的都是事务开始时的快照版本

    如何避免幻影读

    通过 next-key lock 锁机制,是由index-row lock和gap lock组合成的

    如,条件为col2>5,会在区间上[1,5],(5,正无穷)加index-row lock

    08:30:02[test](;)> set tx_isolation='repeatable-read' ;    
    08:30:49[test](;)> select * from t1;
    +----+------+------+------+------+
    | id | col1 | col2 | col3 | col4 |
    +----+------+------+------+------+
    |  1 |    1 |    1 |    1 |    1 |
    |  2 |    2 |   10 |    2 |   10 |
    +----+------+------+------+------+
    2 rows in set (0.00 sec)
    Query OK,
    0 rows affected (0.00 sec) 08:31:02[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 08:31:05[test](;)> select * from t1 where col2>5 for update; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 2 | 2 | 10 | 2 | 10 | +----+------+------+------+------+ 1 row in set (0.00 sec) 08:30:51[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 08:32:11[test](;)> insert into t1 values(3,3,6,3,6); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

    ---恢复内容结束---

    mysql innodb目前使用范围最广的两种隔离级别为RC和RR,RR修复了RC中所存在的不可重复读

    READ COMMITED

    不可重复读

    在同一事务中两次查看的结果集不同,如下session1的查看结果集受session2提交的事物影响

    05:47:35[test](;)> select @@tx_isolation;
    +----------------+
    | @@tx_isolation |
    +----------------+
    | READ-COMMITTED |
    +----------------+

    session1
    03:28:11[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 03:28:21[test](;)> select * from t1; Empty set (0.01 sec) session2 03:28:27[test](;)> insert into t1 values(1,1,1,1,1); Query OK, 1 row affected (0.00 sec) 03:29:25[test](;)> select * from t1; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 1 | 1 | 1 | 1 | 1 | +----+------+------+------+------+ 1 row in set (0.00 sec)

    幻影读(Phantom Rows)

    什么是幻影读

    同一事务保证了一致性读后,查询时对提交的事务是不可见的,但是变更的时候是可见的,所以就有可能引发幻影读

    为什么会导致幻影读

    对于update或delete操作(可以使用SELECT with FOR UPDATE or LOCK IN SHARE MODE来进行模拟),innodb只加记录锁(满足条件索引记录)而不是gap锁,gap锁只用于外键约束和duplicate key的检查,所以允许另一事务在锁定的记录旁边自由插入新记录

    如col2上有索引,在满足col2>5的条件索引上加索引(对于RC,只在col2为10的索引记录上加X lock),所以在另一会话总插入col2 为非10的记录则会成功

    set tx_isolation='read-committed' ;                                                                                  
    session 1                                                                                                            
    07:46:16[test](;)> begin;                                                                                            
    Query OK, 0 rows affected (0.00 sec)                                                                                 
                                                                                                                         
    07:46:20[test](;)> select * from t1 where col2>5 for update;                                                         
    +----+------+------+------+------+                                                                                   
    | id | col1 | col2 | col3 | col4 |                                                                                   
    +----+------+------+------+------+                                                                                   
    |  2 |    2 |   10 |    2 |    2 |                                                                                   
    +----+------+------+------+------+                                                                                   
    1 row in set (0.00 sec)                                                                                              
                                                                   07:44:48[test](;)> begin;                             
                                                                   Query OK, 0 rows affected (0.00 sec)                  
                                                                                                                         
                                                                   07:46:36[test](;)> insert into t1 values(3,3,6,3,3);  
                                                                   Query OK, 1 row affected (0.00 sec)                   
                                                                                                                         
                                                                   07:46:38[test](;)> commit;                            
                                                                   Query OK, 0 rows affected (0.10 sec)                  
    07:46:31[test](;)> select * from t1 where col2>5;                                                                    
    +----+------+------+------+------+                                                                                   
    | id | col1 | col2 | col3 | col4 |                                                                                   
    +----+------+------+------+------+                                                                                   
    |  3 |    3 |    6 |    3 |    3 |                                                                                   
    |  2 |    2 |   10 |    2 |    2 |                                                                                   
    +----+------+------+------+------+                                                                                   
    2 rows in set (0.00 sec)                                                                                             

    若col2上无索引,也会是同样的结果现象,如果条件字段上无索引,innodb会先将所有行都加上锁,然后返回给server层根据条件筛选,满足条件则释放行锁,不满足条件则不释放

    REPEATABLE READ

    如何实现可重复读

    事物开始时记录当前的快照版本,事务期间读取的都是事务开始时的快照版本

    如何避免幻影读

    通过 next-key lock 锁机制,是由index-row lock和gap lock组合成的

    如,条件为col2>5,会在区间上[1,5],(5,正无穷)加index-row lock

    08:30:02[test](;)> set tx_isolation='repeatable-read' ;    
    08:30:49[test](;)> select * from t1;
    +----+------+------+------+------+
    | id | col1 | col2 | col3 | col4 |
    +----+------+------+------+------+
    |  1 |    1 |    1 |    1 |    1 |
    |  2 |    2 |   10 |    2 |   10 |
    +----+------+------+------+------+
    2 rows in set (0.00 sec)
    Query OK,
    0 rows affected (0.00 sec) 08:31:02[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 08:31:05[test](;)> select * from t1 where col2>5 for update; +----+------+------+------+------+ | id | col1 | col2 | col3 | col4 | +----+------+------+------+------+ | 2 | 2 | 10 | 2 | 10 | +----+------+------+------+------+ 1 row in set (0.00 sec) 08:30:51[test](;)> begin; Query OK, 0 rows affected (0.00 sec) 08:32:11[test](;)> insert into t1 values(3,3,6,3,6); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
  • 相关阅读:
    【模板】辗转相除法
    【模板】冰茶姬(大概是全的?)
    【模板】快速幂
    【模板】线段树-区间修改
    【模板】线段树-单点修改,区间查询
    【模板】dijkstra与floyd
    【模板】SPFA(不完全详解)
    【济南集训】随机分数
    P3205 [HNOI2010]合唱队
    最大子列2
  • 原文地址:https://www.cnblogs.com/Bccd/p/7543903.html
Copyright © 2011-2022 走看看