使用乐观锁时会不会出现死锁?

Posted

技术标签:

【中文标题】使用乐观锁时会不会出现死锁?【英文标题】:Could there be a deadlock when using optimistic locking? 【发布时间】:2016-12-21 04:05:49 【问题描述】:

众所周知,有两种锁定策略:Optimistic vs. Pessimistic locking

悲观锁定是指您锁定记录以供您独占使用 直到你完成它。它的完整性比 乐观锁定,但需要你小心你的 避免Deadlocks的应用程序设计。

还知道,Optimistic Concurrency Control 与 Multi Version Concurrency Control 不同(Oracle 或 MSSQL-Snapshot/MVCC-RC):Optimistic vs Multi Version Concurrency Control - Differences?

但是如果在两个事务中都使用 OCC(Optimistic Concurrency Control) 会在两个事务之间发生死锁吗?

我们可以说乐观锁通过降低一致性来降低死锁的可能性吗?并且只有当每次更新都在一个单独的事务中时,死锁的可能性是 0%,但这是最小的一致性。

【问题讨论】:

【参考方案1】:

恐怕您对乐观并发控制的定义必须非常精确。在 Bernstein、Goodman 和 Hadzilacos 的经典定义中,乐观并发控制允许线程“虚拟地”获取锁,继续更新,然后在事务尝试提交时检查一致性违规。如果发生一致性冲突,事务将被强制中止并重新提交。在这个定义下,死锁是如何发生的并不清楚,因为线程“从不”阻塞等待锁。乐观并发控制的经典定义在实际中并不容易实现。然而,最近在硬件事务内存方面的工作开启了一些可能性,并为这个老问题提供了一些视角。

【讨论】:

谢谢!但是通过使用硬件事务内存实现的乐观并发控制的经典定义 - 它可以具有属性可组合性吗? en.wikipedia.org/wiki/… 此外,似乎使用“可串行化隔离级别”时死锁的可能性最小,任何修改只有在事务提交后才可见,Tom Kyte 说“可串行化是实现高的一种方法吞吐量和更快的响应时间”,从中可以得出结论,线程冲突较少。 asktom.oracle.com/pls/apex/… 通过使用 OCC 是否可以在 MVCC 中实现仅可串行化的隔离级别,或者任何其他:Read-Committed、Repeatable-read、Snapshot? 这应该是正确的答案:OCC 根据定义是无死锁的。 为什么会出现“乐观并发控制的经典定义在实际中不容易实现”。 ?是否有任何参考资料可以解释这一点?谢谢【参考方案2】:

当然。

死锁只是意味着线程 A 持有线程 B 正在等待的锁,而 B 持有 A 正在等待的锁。如果您的应用程序并非设计为在各处以相同的顺序锁定资源,那么无论您的锁定策略如何,都很容易死锁。

假设线程 A 和 B 都想更新父表和子表中的特定行。线程 A 首先更新父行。线程 B 首先更新子行。现在线程 A 尝试更新子行并发现自己被 B 阻塞。同时,线程 B 尝试更新父行并发现自己被 A 阻塞。你有一个死锁。

如果您在 Oracle 中锁定资源的顺序一致(即始终在子项之前锁定父项),则无论您的锁定策略如何,都不会出现死锁。您通常不会在 SQL Server 中遇到死锁,但在 SQL Server 中行级锁升级的可能性使得这不太确定。

【讨论】:

谢谢!因此 Oracle 数据库从不升级锁。锁升级大大增加了死锁的可能性。这是否意味着死锁是乐观并发与多版本并发的另一个区别?但是目前,当乐观并发完成时-读取-检查-修改行,我们是否使用锁?也可以是每个事务在某一时刻只有一个锁,所以不能死锁。 @Alex - 我不确定我是否理解后续内容。为了更新一行,您必须锁定它。乐观锁定和悲观锁定之间的区别在于您是否悲观地锁定行以防万一您可能更新它,或者您是否乐观地等待直到您知道要更新它以获得锁定。您可以编写一个应用程序,将每次更新都作为单独的事务进行。这会减少死锁,但对于数据一致性来说会很糟糕。 是的,谢谢,这就是我想知道的。我们可以说乐观锁通过降低一致性来降低死锁的可能性吗?并且仅当每次更新都在单独的事务中时,死锁的可能性为 0%,但这是最小的一致性。使用一定数量的乐观方法,我们可以在死锁和一致性之间实现必要的权衡。 @Alex - 在 Oracle 中,死锁不是一种权衡。无论您使用的是乐观锁还是悲观锁,如果您正确编写代码,就永远不会出现死锁。在 SQL Server 中,除非在 OLTP 系统中极少出现锁升级的情况,否则您永远不会遇到死锁。如果你的应用程序出现死锁,说明它写得不好。 我发现使用悲观锁定方案避免死锁可能要困难得多。使用这样的方案,您通常会在用户发出修改它的意图时(即,当他第一次编辑行中的任何列时)专门锁定该行。由于您无法控制每个用户编辑他们看到的数据的顺序,因此您无法保证不会发生死锁。在乐观锁定模型中,在保存他们的工作之前,您不会专门锁定任何东西。此时,您知道所有受影响的行,并可以以一致的顺序锁定它们(例如,通过 ID 升序或其他方式)。

以上是关于使用乐观锁时会不会出现死锁?的主要内容,如果未能解决你的问题,请参考以下文章

悲观锁和乐观锁

悲观锁和乐观锁

Mysql:行锁 表锁 乐观锁 悲观锁 读锁 写锁

死锁与悲观锁乐观锁不是一类东西

CAS 与原子操作

JUC - 多线程之悲观锁乐观锁,读写锁(共享锁独享锁),公平非公平锁,可重入锁,自旋锁,死锁