【问题标题】:race condition UPDATE modification of credit column - what happens on rollback?信用列的竞争条件更新修改 - 回滚时会发生什么?
【发布时间】:2010-11-20 23:33:27
【问题描述】:

好的,我尝试搜索并没有找到答案 - 我很好奇 ROLLBACK 如何处理竞争条件。例如:

如果我有一个表 (CompanyAccount),它记录了一家公司有多少积分可供购买(每家公司的数据库表中只有一行)并且可能有来自同一家公司的多个用户可以递减来自单个公司账户的贷方,如果发生 ROLLBACK 时出错怎么办?

例子:

假设:我已经正确编写了更新来计算“信用”新余额,而不是猜测新的信用余额是什么(即我们不试图告诉 UPDATE 语句新的信用余额/价值是什么,我们说取信用列中的任何内容并在 UPDATE 语句中减去我的减量值)...

以下是更新语句的编写示例:

更新 dbo.CompanyAccount SET Credit = Credit - @DecrementAmount WHERE CompanyAccountId = @CompanyAccountId

如果“信用”列有 10,000 个信用。用户 A 导致减少 4,000 个信用,而用户 B 导致减少 1000 个信用。出于某种原因,在用户 A 的递减期间触发了回滚(在 TRANSACTION 期间,大约有 1/2 多张表的行被插入)。如果用户 A 赢得竞争条件并且新余额为 6,000(但尚未提交),如果用户 B 的递减发生在应用回滚之前会发生什么?余额栏是否从 6,000 变为 5,000,然后 ROLLBACK 变为 10,000?

我不太清楚 ROLLBACK 将如何处理这个问题。也许我过于简单化了。如果我误解了 ROLLBACK 的工作原理,或者我需要担心这种风格的其他风险,有人可以告诉我。

感谢您的意见。

【问题讨论】:

    标签: sql-server-2005 transactions race-condition rollback


    【解决方案1】:

    在你给出的例子中不会有问题。

    第一个事务将有一个排他锁,这意味着第二个事务在第一个事务提交或回滚之前不能修改该行。它只需要等待(阻塞)直到锁被释放。

    如果你有多个语句,它会变得有点复杂。您可能应该阅读不同的隔离级别以及它们如何允许或防止“丢失更新”等现象。

    【讨论】:

    • 根据此链接 (msdn.microsoft.com/en-us/library/ms378149.aspx) "如果两个事务使用单个 UPDATE 语句更新行并且不基于先前检索的值进行更新,则在默认隔离级别下不会发生丢失更新已提交的读取。”
    【解决方案2】:

    回滚是事务的一部分,并且在回滚期间将保持锁定。 ACID 中的 *A* tomic。 用户 B 在所有锁都被释放之前不会启动。

    会发生什么:

    • 用户 A 锁定行
    • 在释放锁之前,用户 B 看不到行
    • 用户 A 回滚,释放锁定,从未发生更改。
    • 用户 B 看到行。 -1000 将导致 9000

    但是,如果用户 B 已经读取了余额,那么在更新时可能会不一致。这取决于您实际在做什么以及以什么顺序,因此需要了解isolation levels(以及幻读和不可重复读取的问题)

    SERIALIZABLE 或 REPEATABLE READ 的替代方案可以在事务模式下使用 sp_getapplock 来对事务的部分进行信号量。

    【讨论】:

      猜你喜欢
      • 2017-12-29
      • 1970-01-01
      • 2014-11-06
      • 2022-11-04
      • 2021-09-27
      • 1970-01-01
      • 1970-01-01
      • 2021-08-27
      • 1970-01-01
      相关资源
      最近更新 更多