mysql repeatable-read 一次利用间隙锁解决幻读案例
源:http://fucheng.blog.51cto.com/2404495/1619359
评:
repeatable-read是Mysql默认事务隔离级别!能解决脏读以及不可重复读的问题,但可能出现幻读的情况
不可重复读:在一个未提交的事务里,二次查询结果可能不相同,因为在这个事务执行过程中,外面的事务可能对这个数据集进行了修改并提交!
幻读:一个事务在操作过程中!有别的事务对此数据集进行了修改并提交,但这些操作第一个事务读不到,等到这个事务提交的时候,便有可能引起明明插入的数据没有查询到,但却出现插入重复的错误!
不可重复读与幻读的区别:
不可重复读是能读到其它事务已经提交的数据,幻读是读不到其它事务已提交的数据!
间隙锁:间隙锁主要用来防止幻读,用在repeatable-read隔离级别下,指的是当对数据进行条件,范围检索时,对其范围内也许并存在的值进行加锁!当查询的索引含有唯一属性(唯一索引,主键索引)时,Innodb存储引擎会对next-keylock进行优化,将其降为recordlock,即仅锁住索引本身,而不是范围!若是普通辅助索引,则会使用传统的next-keylock进行范围锁定!
/*
幻读案例:有个表(id字段为非唯一辅助索引)每次插入前需查询这字段的最大值,然后再取最大值+1插入!
事务1:事务2:
selectmax(id)frome;insertintoevalues(11)
10commit;
insertintoevalues(11)
commit;
ERROR1062(23000):Duplicateentry'11'forkey'id'
在上述事务1中明明查询最大值为10,但插入最大值+1的时候却报错!
解决方案:利用mysql间隙锁
事务1:事务2:
selectmax(id)fromelockinsharemode;
(此时会对id为10以上的所有不存在的值加间隙锁)
10insertintoevalues(11);
insertintoevalues(11)commit;此时提交会一处于等待状态,
commit;
*/
总结:
表a
id
3
5
6
9
在运用间隙锁的过程中,(-00+00为负正无穷大)
如果条件为wherea=5这样的条件,则间隙锁锁住的范围为(-00,3),(3,5),(5,6),(6,9),(9,+00)
如果条件为wherea>5,则间隙锁锁住的范围为(5,+00)
如果为selectmax(id),则锁住的范围为(max(id),+00)
另外在测试间隙锁的过程中遇到了innodb锁全表,全表所有间隙上锁的情况!这篇博文里的提到:
http://blog.itpub.net/29254281/viewspace-1401413/
本文出自“夫臣”博客,请务必保留此出处http://fucheng.blog.51cto.com/2404495/1619359