MySQL中的事务隔离级别

本文深入探讨了SQL标准下的四个事务隔离级别——脏读、不可重复读、幻读及其对应实现,通过MySQL实例展示了InnoDB的可重复读隔离级别的特性与优势,特别强调了如何避免幻读现象。

 

SQL 标准用三个必须在并行的事务之间避免的现象定义了四个级别的事务隔离。 这些不希望发生的现象是: 

  • 脏读(dirty reads)


一个事务读取了另一个未提交的并行事务写的数据。 

  • 不可重复读(non-repeatable reads)


一个事务重新读取前面读取过的数据, 发现该数据已经被另一个已提交的事务修改过。 

  • 幻读(phantom read)


一个事务重新执行一个查询,返回一套符合查询条件的行, 发现这些行因为其他最近提交的事务而发生了改变。

 

SQL 事务隔离级别 

离级别 脏读(Dirty Read)         不可重复读(NonRepeatable Read)幻读(Phantom Read)
读未提交(Read uncommitted)可能可能可能
读已提交(Read committed)不可能可能可能
可重复读(Repeatable read)不可能不可能可能
可串行化(Serializable )不可能不可能不可能

 

在MySQL中默认事务隔离级别是可重复读(Repeatable read).可通过SQL语句查询:
查看InnoDB系统级别的事务隔离级别:

    mysql> SELECT @@global.tx_isolation; or  show variables like "%tx%";

结果:
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ       |
+-----------------------+
1 row in set (0.00 sec)

查看InnoDB会话级别的事务隔离级别:

  mysql> SELECT @@tx_isolation;

结果:
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)

修改事务隔离级别:

    mysql> set global transaction isolation level read committed;

    Query OK, 0 rows affected (0.00 sec)

    mysql> set session transaction isolation level read committed;

    Query OK, 0 rows affected (0.00 sec)

InnoDB的可重复读隔离级别和其他数据库的可重复读是有区别的,不会造成幻象读(phantom read),所谓幻象读,就是同一个事务内,多次select,可以读取到其他session insert并已经commit的数据。下面是一个小的测试,证明InnoDB的可重复读隔离级别不会造成幻象读。测试涉及两个session,分别为session 1和session 2,隔离级别都是repeateable read,关闭autocommit

    mysql> select @@tx_isolation;
  
    +-----------------+
    | @@tx_isolation  |
    +-----------------+
    | REPEATABLE-READ |
    +-----------------+
    1 row in set (0.00 sec)
   
    mysql> set autocommit=off;

    Query OK, 0 rows affected (0.00 sec)

session 1 创建表并插入测试数据

     mysql> create table test(i int) engine=innodb;
    Query OK, 0 rows affected (0.00 sec)

    mysql> insert into test values(1);
    Query OK, 1 row affected (0.00 sec)

session 2 查询,没有数据,正常,session1没有提交,不允许脏读
     mysql> select * from test;
     Empty set (0.00 sec)

session 1 提交事务

    mysql> commit;
    Query OK, 0 rows affected (0.00 sec)

session 2 查询,还是没有数据,没有产生幻象读
                        
    mysql> select * from test;
    Empty set (0.00 sec)
                        
                        
以上试验版本:
                        
    mysql> select version();
    +-------------------------+
    | version()               |
    +-------------------------+
    | 5.0.37-community-nt-log |
    +-------------------------+
    1 row in set (0.00 sec)
 
 
 


--------------------

什么是脏读、不可重复读、幻读  by Oneyearlater的理解


两个事务操作同时一个表table

1. 脏读 :A  update了row 1, 但是还没有commit,这时候B 读取了row1当中的数据(select * from table where id=row1);但是A 继续update,update到row 99 发生了错误,A发生rollback,那么B 读到的就是脏数据 -- row1 和数据库当中的不一致。

2. 不可重复读 : B 读取 row2(select * from table where id=row2), 然后A update了row2, B再读取 row2, 那么两次B读到数据就不一样了。

3. 幻读 :   B 对table进行计数统计(select count(*) from table),row3 属于符合条件的结果之一,然后A  delete row3,(或者insert  了一条新记录row4,row4也是符合条件的结果); B对table进行计数统计, 那么两次B读到count就不一样了。


mysql给出的资料当中也指出了,   If there are multiple INSERT statements, they are queued and performed in sequence, concurrently with the SELECT statements. The results of a concurrent INSERT may not be visible immediately.   
(from http://dev.mysql.com/doc/refman/5.5/en/concurrent-inserts.html)

话说幻读在大部分生产环境下是可以接受的,要消除只有串行化A和B。。。

下面是别人总结的区别:
不可重复读的重点是修改 : 
同样的条件 ,   你读取过的数据 ,   再次读取出来发现值不一样了 
幻读的重点在于新增或者删除 
同样的条件 ,   第 1 次和第 2 次读出来的记录数不一样 


l          READ_UNCOMMITTED 会出现脏读、不可重复读、幻读 ( 隔离级别最低,并发性能高 )

l          READ_COMMITTED  会出现不可重复读、幻读问题(锁定正在读取的行)

l          REPEATABLE_READ 会出幻读(锁定所读取的所有行)   <== mysql 默认在此,大部分的rmdbd也会把隔离级别设置在此

l          SERIALIZABLE 保证所有的情况不会发生(锁表)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值