【问题标题】:Can I mark a database record as "in use"?我可以将数据库记录标记为“正在使用”吗?
【发布时间】:2013-06-02 16:24:39
【问题描述】:

假设我在数据库服务器上有一个表(我们称之为myTable),我正在编写一个桌面客户端应用程序,允许您修改myTable 中的记录。我不希望两个用户能够编辑同一条记录,即,如果用户 A 编辑记录 1 并且用户 B 尝试执行相同操作,他会收到通知,该记录当前已被用户 A“锁定”。

我确定这是一个常见问题,所以我想知道是否有规范的解决方案。


有一个明显的解决方案,但它也有一个明显的缺点:

  • myTable中添加字段inUseBy,当用户开始编辑记录时将其设置为用户名,并在用户完成后将其清除,例如

    function editRecord(recordId):
        begin transaction
        if (select lockedBy from myTable where id = recordId) is not empty:
            commit
            show "Sorry, record already in use by ..."
        else
            update myTable set lockedBy = current_user() where id = recordId
            commit
            show UI window to let user edit and update record
            update myTable set lockedBy = empty where id = recordId
    

    缺点:如果用户 A 的应用程序崩溃,记录将保持锁定状态。

以下方法乍一看似乎合适,但不能解决问题:

  • 使用数据库锁来锁定记录 1。这只会导致用户 B 超时。我需要将记录锁定在应用程序级别而不是数据库级别。

【问题讨论】:

标签: sql-server database language-agnostic locking


【解决方案1】:

一种常见的方法是使用 ROWVERSION 进行乐观并发。

Rowversion 是一种数据类型(您可以将其添加为新列),该数据类型会在行更新时更新。

因此,您选择了行,包括 rowversion 列。当您发回更新时,请确保行版本匹配 - 通过执行更新并添加“WHERE Rowversion = TheRowversionIGotEarlier”并查看@@ROWCOUNT 是否不为 0 - 如果为零,则可以假设有人修改了该行因为您阅读了它,您可以将该消息返回给用户。

http://www.mssqltips.com/sqlservertip/1501/optimistic-locking-in-sql-server-using-the-rowversion-data-type/

您问的是悲观并发,正如这个答案和对您问题的评论所说 - 请考虑乐观并发。考虑一下您的模型,它将如何处理开始编辑记录然后去吃午饭的人?或者如果他们从来没有吃过午饭回来?如果出于关键业务原因必须同时编辑记录怎么办?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-20
    • 2023-04-05
    • 2012-08-24
    • 1970-01-01
    • 1970-01-01
    • 2011-01-18
    相关资源
    最近更新 更多