Mysql事务隔离水平(Isolation Levels)简介

来源:互联网 发布:windows 商业版 编辑:程序博客网 时间:2024/06/08 07:12

Mysql有4种事务隔离水平(Transaction Isolation Levels) 

1.未提交读(Read Uncommitted):一个事务可能读取到其他会话中未提交事务修改的数据,就是脏读(dirty read)。这种隔离水平是没有实际意义的。 

2.提交读(Read Committed):从字面理解的意思是事务只能读取到已经提交的数据。在High Performance Mysql一书的解释是: 

a transaction will see only those changes made by transactions that were already committed when it began, and its changes won’t be visible to others until it has committed.


单纯从字面上还是有点绕口。其实比较简单,就是一个事务里面如果有对一个数据的多次访问,Read Committed不保证每次访问的结果都一样。如果别的会话在该事务2次访问数据之间对该数据进行了修改或者删除,2次访问就会得到不一样的结果。 

所以这个隔离水平也叫nonrepeatable read(不可重复读)。Oracle缺省使用这个隔离水平。 

3. 可重复读(Repeated Read):可重复读,结合上面对提交读的解释,这个隔离水平就很好理解。一个事务里面如果有对一个数据的多次访问,Repeated Read会保证在该事务内所有访问结果都一致,不管其他会话是否尝试对该数据修改或者删除。Mysql的InnoDB缺省使用这个隔离水平。 

可重复读可能会带来幻读(phantom read)的问题。幻读是指一个事务里面如果有对一个数据的多次访问,后一次的访问读到别的会话插入的数据。(别的会话刚好插入一个数据满足改访问的where条件)。 

但是mysql innodb通过multiversion concurrency control技术保证了不会发生幻读的情况。 

4. 串行(Serializable):串行化访问,每次读都需要获得表级共享锁,读写相互都会阻塞。串行的最大问题的是并发能力非常低。 

--------------------华丽的分割线--------------------------- 
为了更好的区别Read Committed和Repeated Read,读者可以参考这个例子: 

1) 首先建立一个表: 
CREATE TABLE t1(id int,value int); 
INSERT t1 VALUES(1,1); 

2) 测试Read Committed会出现不可重复读的情况 
同时打开两个的会话,在第一个会话执行以下的sql: 
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 设置Read Committed级别 
START TRANSACTION; 
    SELECT * FROM t1;  
    
    select sleep(10); -- 休眠10秒,等待另一个会话修改数据 
    
    SELECT * FROM t1;   
commit  ; 

在第一个会话休眠期期间,在第二个会话执行以下的SQL: 
update t1 set value = 2 where id =1; 

第一个会话结束后,可以看到两个SELECT的结果是不一样的,第二次select被第二个会话的数据修改影响了。 

3)测试Repeated Read的可重复读能力 
在会话一执行以下SQL: 
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- 设置 repeatable read级别 
START TRANSACTION; 
    SELECT * FROM t1;  
    
    select sleep(10); -- 休眠10秒,等待另一个会话修改数据 
    
    SELECT * FROM t1;   
Commit  ; 

在第一个会话休眠期期间,在第二个会话执行以下的SQL: 
update t1 set value = 3 where id =1; 

第一个会话结束后,可以看到两个SELECT的结果是完全一样的,而且第二个会话没有被阻塞,并不是串行的读写来保证可重复读。