我可以将数据库记录标记为“正在使用中”吗?

时间:2013-06-06 15:16:10

标签: sql-server database language-agnostic locking

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

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


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

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

    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进入超时状态。我需要锁定应用程序级别的记录 而不是数据库级别。

1 个答案:

答案 0 :(得分:0)

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

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

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

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

你问的是悲观的并发性,并且正如这个答案和你的问题的评论所说 - 考虑乐观的并发性。考虑一下你的模型,它会如何处理开始编辑记录然后去吃午餐的人?或者,如果他们从未从午餐回来?如果必须在此期间编辑记录,出于关键业务原因该怎么办?