Read Committed 不足在哪里?

5 transaction isolation-level

维基百科说Read Committed 容易出现不可重复读取。但是,我可以简单地在我的事务中缓存第一个读取结果(制作快照)并释放数据库锁以让其他事务更新读取行。实际上,我以 RC 隔离为代价实现了重复读取,因此比可重复读取提供的性能更高。没有什么不好的事情发生,我可以像使用可重复读取隔离一样安全,对吗?不,我想对我读过的数据持有读锁可能有助于防止银行或预订预订中出现一些不良情况。哪个?

我正在寻找的是我的 RR 仿真失败的示例。我已经证明我可以通过在第一次读取访问时缓存数据项来使读取可重复。我想要一个我的模拟不够的例子。这种策略下读完立即释放锁有什么不好?

维基百科的文章和可重复阅读的名称在我看来暗示这就是我们所需要的。但我怀疑可重复读取通过使用共享锁,为了提供比简单读取一致性更重要的东西而牺牲了性能,因为后者可以通过简单的读取提交 + 缓存(快照)组合来实现。我猜读者锁在2PL 中的整个事务中持续存在,并且我们在多个读者/单作者中使用共享/读取锁,其目的不仅仅是在单个事务中提供可重复的读取,因此,Repeatable Read 是隐藏锁定事实的用词不当,它实际上牺牲了比一致性读取更大的性能。

Pau*_*ite 11

隔离级别的选择取决于您的应用程序需要从数据库获得的保证。只有可序列化的隔离才能提供完全的 ACID 隔离;所有其他隔离级别为事务提供较低程度的保护。

Read Committed 承认重复读取中的不一致结果

读提交隔离提供的唯一保证是只读取提交的数据(不允许脏读)。除此之外的任何内容都是特定于实现的。

例如,在 SQL Server 中,使用行版本控制(RCSI)提交的读取还保证了语句级可重复读取和数据库的语句级时间点视图。需要明确的是,在 RCSI 下的同一事务中的多个语句中,这两者都不能保证(这是由快照隔离提供的)。

SQL Server 使用锁定实现读取提交允许同一语句内的重复读取遇到不同的值,并允许数据库从不同的时间点返回数据。

强调一下:多次触及同一行的单个语句可能会遇到不同的值。由于查询优化器在构建物理执行策略方面具有相当大的自由度,因此单独检查 SQL 可能不会导致多次读取。

我可以简单地在我的事务中缓存第一个读取结果,并让其他事务更新...

这是一种有效的方法,如果它满足您正在(或基于)数据所做的任何事情的隔离要求。

没有什么不好的事情发生,我可以像重复读取隔离一样安全,对吗?

一般不会,不会。可重复读 (RR) 隔离比已提交读 (RC) 隔离提供更多保证。具体来说,RR 保证一旦第一次读取数据项,数据在事务的生命周期内不会更改。RR 不保证读取实际上是完全可重复的,因为新数据可能会出现在后续读取(幻像)中。

请注意,实现可以自由地超出每个隔离级别的基本要求,因此某些产品实际上可能在 RC 下提供与 RR 相同的保证(对于 SQL Server 而言并非如此)。事实上,一个实现可以使所有隔离级别等于可序列化,并且仍然符合标准。

不,我想为我读取的数据持有读取锁有助于防止一些不受欢迎的情况......

锁定是一个实现细节。最好考虑在所有情况下(当可能发生多个并发数据更改时)正确使用数据所需的隔离程度

...可能是为了防止预订时出现一些不良情况。哪个?

多个并发数据库事务可以无益地交互的方式仅受想象力的限制。

例如,使用 RC 并缓存读取的值可能会导致更新丢失,在您的事务执行相同操作之前,另一个事务会根据存储的值进行更新。在运行的两个事务的历史方面x:= x + 1

事务 1 读取 x (=1)
事务 2 读取 x (=1) 
事务 2 写入 [x:=x + 1] (=2)
事务 2 提交
事务 1 写入 [x:=x + 1] (=2)
事务 1 提交

只有可序列化的隔离才能保证如果一个事务可以在没有并发活动的情况下产生正确的结果,那么在与并发事务的任何组合竞争时,它将继续这样做。

请注意,这并不意味着并发可序列化事务实际上是按顺序执行的,只是它们将具有与它们相同的效果(以某种未指定的顺序)。

指定任何其他隔离级别涉及权衡:潜在更高的性能和/或并发性,但隔离保证更少。在不同的实现之间,权衡的确切含义是显着不同的。

选择适当的隔离级别需要将应用程序的需求与可用的保证进行比较。此外,您可能需要考虑其他因素,例如事务是否需要数据的时间点视图。

有关 SQL Server 角度的更多信息和一些示例,请参阅我在SQL Server Isolation Levels : A 系列中的文章