大橙子网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
众所周知,Mysql在InnoDB下有四种隔离级别:
创新互联-专业网站定制、快速模板网站建设、高性价比红旗网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式红旗网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖红旗地区。费用合理售后完善,10年实体公司更值得信赖。
未提交读(Read Uncommitted)
提交后读(Read Committed)
可重复读(Repeatable Read)
串行化(Serializable)
其中可重复读(RR)可以避免脏读( a事务读到b事务回滚前的数据)以及可不重复读( a事务在b事务修改提交的前后,两次分别读到的数据不一致)。但是对于幻读(a事务在b事务insert提交前后,两次分别读到的数据不一致),却存在争议。
下面我们来做一个试验:
对于下面这张简单的数据表
id num
1 11
2 22
3 33
我们开启a、b两个事务
a事务 b事务
begin begin
select * from tb ----
---- insert into tb (id,num)values(4,44)
---- commit
select * from tb ----
commit
试验结果:a事务的两次select查询到的结果相同,在后一次查询中没有返回新插入id=4的那条记录。
据此,很多人判断说RR隔离级别下“不存在”幻读。
但果真如此吗?----
出现上面的试验结果,是因为在RR隔离级别事务下,Mysql会对前一次select的结果快照。所以第二次select其实是快照读(这也正是RR隔离级别下能够避免不可重复读的策略)。
如果我们把试验条件稍作修改,同样开启a、b两个事务:
a事务 b事务
begin begin
select * from tb ----
---- insert into tb (id,num)values(5,55)
---- commit
update tb set num=num+1 ---- #此处a事务做一次修改操作
select * from tb ----
commit
试验结果:在a事务的第二次select中出现了b事务新插入的id=5的记录。
由于做了update操作,之前的快照失效了,所以说RR隔离级别下的快照策略并没能真正避免幻读。
ps. 假如给第二次的select查询上锁(无论是共享锁还是排它锁),也会得到同样的结果,都会令快照失效。
见图,主要是select xx for update,又或者是update语句更新了,使用了当前读。所以后面再次select(13行)出现幻读,如果只是select的话(10行不是update,是个select),是不会出现幻读的情况,因为符合mvcc规则,用的还是一开始的快照。
todo:看下10行是update的情况下的内容:SELECT * FROM information_schema . INNODB_TRX
如果10行,update的id为1,则不会出现幻读的情况,这里因为update的时候把session2里的更新到了
幻读的定义是指,一个事务开启后,执行前后两次查询,两次查询中出现了新的数据,幻读仅针对数据的新增。
比如: 表t中,id为主键,目前有数据1,5,10,20四条。
开始一个事务A,前后两次执行 select * from t where id 10 for update;
开启一个事务B,在事务A第二次执行查询前,执行insert into t values( 2,...); 并提交事务(请暂时忽略这里能否成功执行!)。
此时在RC、RR隔离级别下都会导致事务A第二次查询能够查询到 事务B新增的数据 id = 2。
RC级别下能够看到不同结果就不做解释了。
对于RR隔离级别下,有了MVCC版本控制为什么还能读取到不同的结果呢?
这里要归功于 "for update"。
"for update" 会将快照读变为当前读,在当前读场景中,会自动读取最新的数据,而非快照数据。
分析一下,锁与当前读关系。了解什么情况下会加锁。了解 意向锁、共享锁、排它锁区别及各自在什么情况下使用。
行锁的概念都清楚,这里就不做补充了。
间隙锁实际上是指一个区间。
我们都知道,InnoDB 在RR事务隔离级别下解决幻读问题就是通过Next Key Lock (间隙锁+行锁)来实现的。而且,很多地方也有提到,如果对于读一致性要求不高的场景可以考虑使用RC隔离级别,允许幻读的发生。
还是上边说的那个实例,略微改动:
比如: 表t中,id为主键,目前有数据1,5,10,20四条。
开始一个事务A,前后三次分别执行
开启一个事务B,在事务A执行update前,执行insert into t values( 2,...); 并提交事务。
此时我们知道,事务A中第二次查询能够查到 事务B新增的数据,也就是产生了幻读。那么,按照SQL执行的顺序来说,事务B
什么是幻读?
幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。
首先快照读是不存在幻读的,只有当前读(实时读)才存在幻读的问题。
幻读有什么问题?
select ...for update语句就是将相应的数据行锁住,但是如果存在幻读,就把for update的语义破坏了。
如何解决幻读?
产生幻读的原因是,行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的“间隙”。因此,为了解决幻读问题,InnoDB只好引入新的锁,也就是间隙锁(Gap Lock)。间隙锁和行锁合称 next-key lock , 每个next-key lock是前开后闭区间 。
总结