我有一部分应用程序不断更新表行(1-100行)中的值。 由于这种数据完整性很重要,我在读取和更新这些行的函数中使用SERIALIZABLE锁定事务。
现在我的问题是,如果我在一个事务当前使用的行上执行一个简单的只读SELECT(没有锁定),我可能会得到一个DEADLOCK异常吗? 那么这意味着即使在简单的SELECT情况下,我仍然需要DEADLOCK的重试机制吗?
答案 0 :(得分:3)
现在我知道你的具体业务场景是什么(来自评论),这就是你如何做一些像你提出的建议,而不必实现可序列化的隔离
CREATE PROCEDURE [dbo].[updateUserState] (@UserID int)
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN TRANSACTION
SELECT [State]
FROM [dbo].[UserState] WITH (UPDLOCK)
WHERE [UserID] = @UserID;
IF ([State] = 'logged out')
BEGIN
UPDATE [us]
SET [State] = 'logged in'
FROM [dbo].[UserState] AS [us]
WHERE [UserID] = @UserID;
END
COMMIT TRANSACTION
END
请注意,这是简化的,但提出了主要想法。 UPDLOCK
语句上的SELECT
提示是关键。它说“尝试选择数据,因为我将要做更新(你就是这样!稍后)并保持直到交易结束”。在您的示例中,如果T2进入且T1仍在运行,则T2将无法获取更新锁定,因此将等待T1完成(成功或否)。另请注意,明确设置事务隔离级别只是为了完整性; READ COMMITTED
是SQL Server中的默认设置。