• mysql之事务隔离级别


    事务:是一组原子性的SQL查询语句,也可以被看做一个工作单元。

    事务具有的四个特性:原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)

    1.关系数据库标准中的4个事务隔离级别

     

    #未提交读(read uncommitted): 允许脏读,也就是可能读取到其他会话中未提交事务修改的数据

    #提交读(read committed): 只能读取到已经提交的数据。oracle等多数数据库默认都是该级别

    #可重复读(repeated read): 可重复读。在同一个事务内的查询都是事务开始时刻一致的,innodb的默认级别。

      在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读

    #串行读(serializable): 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

     

     

    2.事务并发导致的几个问题

     

    #更新丢失(Lost Update);

    #脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。

    #不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。

    #幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

    有关以上这几个问题的理解,请参考:http://www.cnblogs.com/hollen/archive/2012/05/13/2498309.html

    隔离级

    脏读可能性

    不可重复读可能性

    幻读可能性

    加锁读

    Read uncommitted

    Read commited

    Repeatable read

    serializable

    测试:

    1. 建测试表,并加入一条数据

    CREATE TABLE `isotest` (

      `id` int(11) NOT NULL AUTO_INCREMENT,

      `name` varchar(50) DEFAULT NULL,

      `score` int(11) DEFAULT NULL,

      PRIMARY KEY (`id`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8

    mysql> insert into isotest (name,score) values('wjlcn',80);

    2. 建立两个连接,假定 AB

    测试隔离级为 read uncommitted 和 read committed

     

    A分别设置隔离级为 read uncommitted

    mysql> set autocommit=off;

    mysql> set session transaction isolation level read uncommitted;

    mysql> select @@tx_isolation;

    +------------------+

    | @@tx_isolation   |

    +------------------+

    | READ-UNCOMMITTED |

    +------------------+

    A

    mysql> update isotest set score=90 where name='wjlcn';

    Query OK, 1 row affected (0.00 sec)

    Rows matched: 1  Changed: 1  Warnings: 0

    mysql> select * from isotest;

    +----+-------+-------+

    | id | name  | score |

    +----+-------+-------+

    |  1 | wjlcn |    90 |

    +----+-------+-------+

    1 row in set (0.00 sec)

    B

    mysql> set session transaction isolation level read uncommitted;

    Query OK, 0 rows affected (0.00 sec)

    mysql> select * from isotest;

    +----+-------+-------+

    | id | name  | score |

    +----+-------+-------+

    |  1 | wjlcn |    90 |

    +----+-------+-------+

    1 row in set (0.00 sec)

    mysql> set session transaction isolation level read committed;

    Query OK, 0 rows affected (0.00 sec)

    mysql> select * from isotest;

    +----+-------+-------+

    | id | name  | score |

    +----+-------+-------+

    |  1 | wjlcn |    80 |

    +----+-------+-------+

    1 row in set (0.00 sec)

    注:在 read uncommitted 隔离级,B上可以脏读,而在read committed上却不可以。




    A

    mysql> commit;

    Query OK, 0 rows affected (0.01 sec)

    B

    mysql> select * from isotest;

    +----+-------+-------+

    | id | name  | score |

    +----+-------+-------+

    |  1 | wjlcn |    90 |

    +----+-------+-------+

    1 row in set (0.00 sec)

    注:当A执行commit后,在read committed上读到了修改后的数据,验证了不可重复读。

    测试隔离级为 repeatable read

    A隔离级设置为:repeatable read  

    mysql> set session transaction isolation level repeatable read;

    测试不可重复读可能性

    A

    mysql> update isotest set score=100 where name='wjlcn';

    B

    mysql> select * from isotest;

    +----+-------+-------+

    | id | name  | score |

    +----+-------+-------+

    |  1 | wjlcn |    90 |

    +----+-------+-------+

    1 row in set (0.00 sec)

    A

    mysql> commit;

    Query OK, 0 rows affected (0.00 sec)

    B

    mysql> select * from isotest;

    +----+-------+-------+

    | id | name  | score |

    +----+-------+-------+

    |  1 | wjlcn |    90 |

    +----+-------+-------+

    1 row in set (0.01 sec)

    注:A事务已经commitB事务中数据仍旧没变,验证了可重复读。

        A事务已经commit,而B事务查的数据没变,在B事务没有提交前,对同一行数据进行update又会怎样?(另外已经验证,会在A事务commit后再进行update

    mysql> commit;

    Query OK, 0 rows affected (0.00 sec)

    mysql> select * from isotest;

    +----+-------+-------+

    | id | name  | score |

    +----+-------+-------+

    |  1 | wjlcn |   100 |

    +----+-------+-------+

    1 row in set (0.00 sec)

    注:只有将B事务commit,重新开始新的事务时,才可以查到更改后的数据。

    测试幻读可能性

    A

    mysql> insert into isotest (name,score) values('kaka',80);

    Query OK, 1 row affected (0.00 sec)

    mysql> select * from isotest;

    +----+-------+-------+

    | id | name  | score |

    +----+-------+-------+

    |  1 | wjlcn |   100 |

    |  2 | kaka  |    80 |

    +----+-------+-------+

    2 rows in set (0.00 sec)

    B

    mysql> select * from isotest;

    +----+-------+-------+

    | id | name  | score |

    +----+-------+-------+

    |  1 | wjlcn |   100 |

    +----+-------+-------+

    1 row in set (0.00 sec)




    A

    mysql> commit;

    Query OK, 0 rows affected (0.00 sec)

    B

    mysql> select * from isotest;

    +----+-------+-------+

    | id | name  | score |

    +----+-------+-------+

    |  1 | wjlcn |   100 |

    +----+-------+-------+

    1 row in set (0.00 sec)

    注:此时用

    //mysql> select * from isotest lock in share mode;

    //mysql> select * from isotest for update;

    //可以查到2条记录InnoDB提供了这样的机制,在默认的可重复读的隔离级别里,可以使用加锁读去查询最新的数据。



    mysql> update isotest set score=180;

    Query OK, 2 rows affected (0.00 sec)

    Rows matched: 2  Changed: 2  Warnings: 0

    mysql> select * from isotest;

    +----+-------+-------+

    | id | name  | score |

    +----+-------+-------+

    |  1 | wjlcn |   180 |

    |  2 | kaka  |   180 |

    +----+-------+-------+

    2 rows in set (0.00 sec)

    怎么啦?咋多出一行? 幻读来了……

    innodb repeatable read可以避免幻读又是怎么回事?

    MySQL InnoDB的可重复读并不保证避免幻读,需要应用使用加锁next-key locks读来保证。

    测试隔离级为 serializable

    A:

    mysql> set session transaction isolation level serializable;

    mysql> update isotest set score=300 where id=4;

    Query OK, 1 row affected (0.00 sec)

    Rows matched: 1  Changed: 1  Warnings: 0



    B:

    mysql> set session transaction isolation level serializable;

    Query OK, 0 rows affected (0.00 sec)

    mysql> select * from isotest;

     

    此时,B事务会被阻塞,因为A事务要个更新id=4 这一行,因此给这行加上了排它锁,B事务再将给 其加上共享锁将会失败。使用A事务commit之后,B事务才会往下执行

     

  • 相关阅读:
    伐木工和森林的故事(一)
    EclipsePDT PHP的开发环境配置
    奇怪的using
    [团队开发]SERVER2008下无法安装VS2008 SP1 和 TFS2008 SP1补丁
    写在七夕
    一点点的松懈,就可以毁掉自己!
    2008,到今天我不后悔
    细节决定成败,注意的事情需要做到,而不是听完了当耳边风
    正视差距,展望2008!
    ZendStudio5.5调式环境配置
  • 原文地址:https://www.cnblogs.com/hancf/p/2660422.html
Copyright © 2020-2023  润新知