是否可以将数据库记录标记为“正在使用”?

Can I mark a database record as "in use"?

提问人:Heinzi 提问时间:6/6/2013 更新时间:6/6/2013 访问量:116

问:

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

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


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

  • 添加一个字段,在用户开始编辑记录后将其设置为用户的名称,并在用户完成后将其清除,例如inUseBymyTable

    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 数据库 与语言无关的 锁定

评论

0赞 Dave K 6/6/2013
blog.sqlauthority.com/2012/11/15/......
0赞 StuartLC 6/6/2013
看起来您正在谈论悲观的并发模式。也看看乐观的并发性 - stackoverflow.com/questions/659489/...

答:

0赞 Meff 6/6/2013 #1

一种常见的方法是使用 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/

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