Open seaswalker opened 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 隔离级别能否防止幻读?
saveOrUpdate
(a, b)
select
SERIALIZABLE
由下面这个例子引出. 假设A事务要执行下面的操作:
假如在查询和
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 隔离级别能否防止幻读?