【问题标题】:Preferred database/webapp concurrency design when multiple users can edit the same data当多个用户可以编辑相同数据时首选的数据库/webapp 并发设计
【发布时间】:2010-10-24 13:19:05
【问题描述】:

我有一个内部使用的 ASP.NET C# 业务 webapp。随着我们的成长,我们遇到的一个问题是原始设计没有考虑并发检查 - 所以现在多个用户正在访问相同的数据并覆盖其他用户的更改。所以我的问题是 - 对于 webapps,人们通常使用悲观或乐观的并发系统吗?是什么促使人们偏好使用一种而不是另一种,以及需要考虑哪些设计注意事项?

我目前倾向于乐观的并发检查,因为它似乎更宽容,但我担心可能会进行多项相互矛盾的更改。

谢谢!

【问题讨论】:

    标签: c# asp.net database-design web-applications concurrency


    【解决方案1】:

    乐观锁定。
    悲观主义更难实现,并且会在 Web 环境中产生问题。什么动作会释放锁,关闭浏览器?离开会话超时?如果他们确实保存了他们的更改呢?

    您没有指定您正在使用哪个数据库。 MS SQL 服务器有一个时间戳数据类型。不过跟时间没有关系。每次更新行时都会更改一个数字。你不需要做任何事情来确保它被改变,你只需要检查它。您可以通过使用 @KM 建议的上次修改的日期/时间来实现类似的目标。但这意味着您必须记住每次更新行时都要更改它。如果您使用 datetime ,则需要使用具有足够精度的数据类型,以确保您最终不会在应该改变的时候改变值。例如,有人保存一行,然后有人读取它,然后发生另一次保存,但修改后的日期/时间保持不变。除非需要跟踪记录上的最后修改日期,否则我会使用时间戳。

    要检查它,您可以按照@KM 的建议进行操作,并将其包含在更新语句 where 子句中。或者你可以开始一个事务,检查时间戳,如果一切顺利进行更新,然后提交事务,如果没有则返回失败代码或错误。

    保持事务打开(如@le dorfier 建议的那样)类似于悲观锁定,但锁定的数据量可能不止一行。默认情况下,大多数 RDBM 的锁都在页面级别。您还会遇到与悲观锁定相同的问题。

    您在问题中提到您担心更新冲突。这就是锁定肯定会阻止的事情。如果实施得当,无论乐观还是悲观都会完全避免这种情况。

    【讨论】:

    • 我更喜欢上次更改日期而不是时间戳数据类型,因为它包含有用的数据。我们还有一个 LastChgID 来跟踪这个人,这两列都很好显示,而时间戳数据类型列没有显示意义。
    • 如果这类数据已经是必需的,那么没有理由不使用它。我已经相应地更新了我的答案。
    【解决方案2】:

    我同意上面的第一个答案,我们尝试在冲突机会相当低的情况下使用乐观锁定。这可以通过 LastModifiedDate 列或递增 Version 列轻松实现。如果您不确定碰撞的频率,请在某处记录发生的情况,以便密切关注它们。如果您的记录始终处于“编辑”模式,则具有单独的“查看”和“编辑”模式可以帮助减少冲突(假设您在进入编辑模式时重新加载数据)。

    如果冲突仍然很高,悲观锁定更难在 Web 应用程序中实现,但绝对有可能。我们在“租赁”记录(超时锁定)方面取得了很好的成功......类似于您在 TicketMaster 上购买门票时收到的 2 分钟警告。当用户进入编辑模式时,我们将一条记录放入“锁定”表中,超时为 N 分钟。如果其他用户尝试编辑具有活动锁定的记录,他们将看到一条消息。您还可以通过在页面的任何回发上更新租约,甚至使用 ajax 计时器来实现长表单的保持活动。你也没有理由不能用上面提到的标准乐观锁来支持它。

    许多应用需要结合使用这两种方法。

    【讨论】:

      【解决方案3】:

      对于许多处理相同记录的人来说,这是一个简单的解决方案。

      当您加载数据时,获取上次更改日期,我们在表格上使用 LastChgDate

      当您保存(更新)数据时,将“AND LastChgDate=previouslyLoadedLastChgDate”添加到 where 子句。如果更新时的行数=0,则在“其他人已保存此数据”处发出错误并回滚所有内容,否则将保存数据。

      我通常只对头表而不是明细表执行上述逻辑,因为它们都在一个事务中。

      【讨论】:

      • 这里要注意的一件事是,如果在 Date 列的分辨率范围内发生 2 次更新,您的逻辑将失败。这是一个非常罕见的边缘情况,但它仍然可能发生。
      • @Glen,一个会获得锁(记住它在事务中),另一个不会,它会等待,然后当它有机会更新时,日期会有所不同。
      【解决方案4】:

      我假设您遇到了“丢失更新”的问题。

      作为经验法则,我使用悲观锁定来解决这个问题,当发生冲突的可能性很高(或事务寿命很短)时,我使用乐观锁定,当发生冲突的可能性很低(或事务寿命很长,或者你的业务规则包含多个事务)。

      您确实需要了解适用于您的情况并做出判断。

      【讨论】:

      • 另外,我永远不会把悲观锁放在它等待用户编辑的地方。
      • @Glen 说“这里要注意的一件事是,如果在 Date 列的分辨率内发生 2 次更新,您的逻辑将失败。这是一种非常罕见的边缘情况,但它仍然可能发生。”但是,一个会获得锁(记住它在事务中),另一个不会,它会等待,然后当它有机会更新时,日期会有所不同。
      猜你喜欢
      • 2020-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-12
      • 2016-01-19
      • 1970-01-01
      • 2017-01-04
      相关资源
      最近更新 更多