我在SQL Server数据库中有一个患者表。客户端连接到数据库并检出其中一个患者并对其进行一些操作并在之后保存。
由于多个客户可能同时访问患者。我想实现悲观锁定机制,这样如果一个客户端可以一次获得对特定患者的锁定。
此外,如果其中一个客户端锁定特定患者并且崩溃或关闭客户端应用程序,则应释放锁定。如果发生崩溃,当我们检测到客户端与数据库的连接关闭时,应该释放锁。
我发现我可以使用sp_getapplock
和sp_releaseapplock
来实现此目的并在调用@LockOwner = 'Session'
时指定sp_getapplock
,这可以确保在数据库发布后锁定被释放与客户的会话结束。
从代码中,我调用数据库中的存储过程来获取锁。这会正确获取锁定,如果我关闭客户端应用程序或客户端应用程序崩溃,则锁定被释放。这就像我想要的那样。
当我调用另一个应该释放锁的存储过程时,就会出现问题。一旦输入存储过程,锁定就会被释放,然后我们甚至会执行sp_releaseapplock @patientId, @LockOwner = 'Session'
实际应该释放锁定的行。
我尝试创建一个空的存储过程(只是注释掉了
DECLARE @result int
EXEC @result = sp_releaseapplock @patientId, @LockOwner = 'Session'
此存储过程仍会释放我使用sp_getapplock
获取的锁。我似乎无法理解为什么会这样。它应该只在我明确调用`sp_releaseapplock @patientId,@ LockOwner ='Session'``
CREATE PROCEDURE [dbo].[uspReleaseAppLock]
@patientId nvarchar(max), -- Patient ID
@ReturnValue int Output
AS
BEGIN
DECLARE @result int
EXEC @result = sp_releaseapplock @patientId, @LockOwner = 'Session'
SET @ReturnValue = @@SPID
END
有人能告诉我为什么会这样吗?我在这里错过了什么?我检查了两个存储过程(用于获取和释放锁)的会话ID是相同的,因此看起来似乎没有为每次调用存储过程的实体框架工作创建新会话。还有其他一些我无法理解的事情。有什么想法吗?
答案 0 :(得分:0)
老问题,所以你可能已经想出了什么,但我觉得有必要回答。对我而言,您正在尝试在数据存储级别执行应用程序级逻辑。我想我会做的是在记录上放置一个CheckedOut位标志。然后,当用户检出患者时,该标志被设置为真。在允许其他用户检出之前,应用程序将检查以确保该标志为false。一旦原始用户检查患者回到标志中,就会将其与任何更改一起设置为假。
只是一个想法。