sp执行时阻止读取行

时间:2010-07-29 13:09:43

标签: .net sql sql-server transactions locking

我有很多.NET进程从SQL Server 2008数据库表读取消息并一次处理一个。我实现了一个简单的SP来“锁定”任何一个进程正在读取的行,以避免任何两个进程处理同一行。

BEGIN TRAN

SELECT @status = status FROM t WHERE t.id = @id
IF @status = 'L'
BEGIN
    -- Already locked by another process. Skip this
    RETURN 0
END
ELSE
    UPDATE t SET status = 'L' WHERE id = @id
    RETURN 1
END

COMMIT

然而,这是有缺陷的:有时一行被“锁定”并处理两次。我怀疑存在并发问题:两个进程在更新之前读取状态。

我认为这可以通过以某种方式实现读取块来解决(即使事务块读取),但我不确定如何执行此操作。有人可以帮忙吗?

提前多多感谢

赖安

2 个答案:

答案 0 :(得分:3)

为什么不用

替换整个事物
UPDATE t SET status = 'L' WHERE id = @id and status <> 'L'
RETURN @@ROWCOUNT

这将避免2次表访问并保持锁定打开超过必要的时间。

答案 1 :(得分:2)

你尝试过使用:

SELECT @status = status FROM t (UPDLOCK) WHERE t.id = @id

有关详细信息,请参阅this链接。

您缺少的是SELECT语句通常不会锁定该行,因此如果一个进程执行了SELECT但尚未执行UPDATE ,然后另一个进程出现并执行SELECT,然后它将返回该行,因为你还没有锁定它。

通过使用UPDLOCK,您可以使用SELECT语句锁定该行,并阻止其他进程将其恢复,直到第一个进程提交事务,这是您想要的行为。

修改 当然,像马丁所说的那样用一条陈述来做这件事是最简单的方法,你可以避免必须处理锁定问题。