两阶段锁定真的可以防止更新丢失吗?
Does two phase locking actually prevent lost updates?
双阶段锁定claimed是确保串行执行的解决方案。但是,我不确定它如何充分解决读-修改-写周期中丢失更新的问题。我可能忽略/误解了这里的锁定机制!
例如,假设我们有一个使用 2PL 的数据库 运行:
给定一个带有整数列 email_count
的 SQL table account
,假设我们的数据库中有以下记录:
| ID | email_count |
| ----- | ----- |
| 1 | 0 |
现在假设我们有两个并发执行的事务,T1
和 T2
。两个事务都会从 ID = 1 的 accounts
读取 email_count
,将计数值增加 1,然后写回结果。
这是 2PL 不 似乎解决丢失更新问题的一种情况(T1 代表事务 1):
T1 -> 获得非独占共享读锁。从 email_count
中读取 ID = 1。得到结果 0。应用程序设置一个新值 (0 + 1 = 1) 以供稍后写入。
T2 -> 也获得一个非独占的共享读锁。从“email_count”读取 ID = 1。得到结果 0。应用程序还设置一个新值(使用现在过时的前提条件),即 1 (0 + 1 = 1)。
T1 -> 获得独占写锁并将新值 (1) 写入我们的记录。这将阻止 T2 写入。
T2 -> 尝试获取写锁以便写入值 1,但被迫等待 T1 完成其事务并释放所有 T1 自己的锁。
现在我的问题是:
一旦 T1 完成并释放它的锁(在我们的 2PL 的“收缩”阶段),T2 仍然 有一个陈旧的 email_count
值1! 所以当 T1 完成并且 T2 继续写入时(email_count
= 1),我们将“丢失”来自 T1 的原始更新。
如果T2有read-lock,T1在T2释放读锁之前无法获得排它锁。因此,您描述的执行顺序不会发生。 T1 将被拒绝写锁,T2 继续事务。
双阶段锁定claimed是确保串行执行的解决方案。但是,我不确定它如何充分解决读-修改-写周期中丢失更新的问题。我可能忽略/误解了这里的锁定机制!
例如,假设我们有一个使用 2PL 的数据库 运行:
给定一个带有整数列 email_count
的 SQL table account
,假设我们的数据库中有以下记录:
| ID | email_count |
| ----- | ----- |
| 1 | 0 |
现在假设我们有两个并发执行的事务,T1
和 T2
。两个事务都会从 ID = 1 的 accounts
读取 email_count
,将计数值增加 1,然后写回结果。
这是 2PL 不 似乎解决丢失更新问题的一种情况(T1 代表事务 1):
T1 -> 获得非独占共享读锁。从 email_count
中读取 ID = 1。得到结果 0。应用程序设置一个新值 (0 + 1 = 1) 以供稍后写入。
T2 -> 也获得一个非独占的共享读锁。从“email_count”读取 ID = 1。得到结果 0。应用程序还设置一个新值(使用现在过时的前提条件),即 1 (0 + 1 = 1)。
T1 -> 获得独占写锁并将新值 (1) 写入我们的记录。这将阻止 T2 写入。
T2 -> 尝试获取写锁以便写入值 1,但被迫等待 T1 完成其事务并释放所有 T1 自己的锁。
现在我的问题是:
一旦 T1 完成并释放它的锁(在我们的 2PL 的“收缩”阶段),T2 仍然 有一个陈旧的 email_count
值1! 所以当 T1 完成并且 T2 继续写入时(email_count
= 1),我们将“丢失”来自 T1 的原始更新。
如果T2有read-lock,T1在T2释放读锁之前无法获得排它锁。因此,您描述的执行顺序不会发生。 T1 将被拒绝写锁,T2 继续事务。