不可重复读和幻影读的区别是什么?
我读过维基百科上的隔离(数据库系统)文章,但我有一些怀疑。在下面的例子中,将会发生什么:不可重复读取和幻影读取?
# # # #事务
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1
# # # #输出:
1----MIKE------29019892---------5000
# # # #事务B
UPDATE USERS SET amount=amount+5000 where ID=1 AND accountno=29019892;
COMMIT;
# # # #事务
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1
另一个疑问是,在上面的示例中,应该使用哪个隔离级别?,为什么?
读现象
脏读:从另一个事务读取未提交的数据
不可重复读取:从另一个事务的UPDATE查询中读取COMMITTED数据
幻影读取:从另一个事务的INSERT或DELETE查询中读取COMMITTED数据
注意:来自另一个事务的DELETE语句,在某些情况下也有非常低的概率导致不可重复读取。不幸的是,当DELETE语句删除当前事务正在查询的同一行时,就会发生这种情况。但这种情况很少见,在每个表中都有数百万行的数据库中更不可能出现这种情况。在任何生产环境中,包含事务数据的表通常都有很大的数据量。
此外,我们还可以观察到,在大多数用例中,更新作业可能比实际的INSERT或delete作业更频繁(在这种情况下,仅存在不可重复读取的危险-在这些情况下不可能出现幻影读取)。这就是为什么update与INSERT-DELETE处理方式不同,导致的异常命名也不同。
处理insert - delete(而不仅仅是处理update)还需要额外的处理成本。
不同隔离级别的好处
READ_UNCOMMITTED什么也阻止不了。这是零
隔离级别
READ_COMMITTED只阻止一种,即脏读
REPEATABLE_READ防止两种异常:脏读和
不可重复读
SERIALIZABLE可以防止所有三种异常:脏读,
不可重复读取和幻影读取
那么为什么不始终设置事务SERIALIZABLE呢?好吧,上述问题的答案是:SERIALIZABLE设置使事务非常慢,这也是我们不希望看到的。
实际上,事务时间消耗的速率如下:
Serializable > repeatable_read > read_committed > read_uncommitted
所以READ_UNCOMMITTED设置是最快的。
总结
实际上,我们需要分析用例并确定隔离级别,以便优化事务时间并防止大多数异常。
注意,数据库在默认情况下可能有REPEATABLE_READ设置。管理员和架构师可能倾向于将此设置作为默认设置,以展示更好的平台性能。