seaswalker / posts

0 stars 0 forks source link

MySQL RR与幻读 #30

Open seaswalker opened 3 years ago

seaswalker commented 3 years ago

由下面这个例子引出. 假设A事务要执行下面的操作:

// a, b上有唯一索引
Data data = jdbc.queryFromDB(a, b);
if (data != null) {
    // 更新操作
} else {
    data = new Data();
    // 唯一索引: on duplicate key update... 并发控制
    jdbc.saveOrUpdate(data);
}

假如在查询和saveOrUpdate之间有B事务插入了一条(a, b)的数据,那么在RR隔离级别下,saveOrUpdate会发生什么?插入还是更新? 答案是更新。 这是幻读吗? 按照定义其实并不是,幻读的定义针对select操作来说的,再做个试验就会发现,select操作并不会看到B事务新插入的数据。但insert/update操作就会互相影响,这其实也是合理的,不然让MySQL引擎如何处理? 所以MySQL在RR下解决幻读了吗?准确来说可能是部分地解决了,除了在下面这种情况下: A事务执行了一个会影响到B事务新增行的update操作,然后再执行select,就又可以看到B事务新增的行了。 所以,上面的并发控制操作在RR下是必须的,不然如果直接insert,那么会出现违反唯一索引错误,如果没有唯一索引,那么就出现了两条数据。 除非,隔离级别是SERIALIZABLE,就不需要这种控制了。还有一点,为了使SERIALIZABLE生效,A和B两个事物必须都是SERIALIZABLE级别。 参考: Innodb 中 RR 隔离级别能否防止幻读?