这是对我正在做的工作的过度简化的解释
我有一个状态列表。应用程序的多个实例将提取状态为NEW
的第一行内容,将状态更新为WORKING
,然后继续处理内容。
使用两个数据库调用很容易做到这一点;首先是SELECT
,然后是UPDATE
。但我希望在一次调用中完成所有操作,以便应用程序的另一个实例不会拉同一行。有点像SELECT_AND_UPDATE
。
存储过程是最好的方法吗?
答案 0 :(得分:8)
您可以使用OUTPUT声明。
DECLARE @Table TABLE (ID INTEGER, Status VARCHAR(32))
INSERT INTO @Table VALUES (1, 'New')
INSERT INTO @Table VALUES (2, 'New')
INSERT INTO @Table VALUES (3, 'Working')
UPDATE @Table
SET Status = 'Working'
OUTPUT Inserted.*
FROM @Table t1
INNER JOIN (
SELECT TOP 1 ID
FROM @Table
WHERE Status = 'New'
) t2 ON t2.ID = t1.ID
答案 1 :(得分:2)
听起来像是一个队列处理场景,您只希望一个进程获取给定的记录。
如果是这种情况,请查看我今天早些时候提供的答案,该答案描述了如何使用事务结合UPDLOCK和READPAST表提示来实现此逻辑: Row locks - manually using them
最好包裹在sproc中。
我不确定这是你想要做什么,所以我没有投票决定关闭。
答案 2 :(得分:1)
不完全,但您可以随后SELECT ... WITH (UPDLOCK)
,然后UPDATE..
。这与原子操作一样好,因为它告诉数据库您将要更新之前选择的内容,因此它可以锁定这些行,从而防止与其他客户端发生冲突。在Oracle和其他一些数据库(MySQL认为)下,语法为SELECT ... FOR UPDATE
。
注意:我认为您需要确保在事务中发生两个语句才能使其正常工作。
答案 3 :(得分:1)
你应该在这里做三件事:
为此,您只需发出以下信息:
SELECT TOP 1 *
FROM mytable (ROWLOCK, UPDLOCK, READPAST)
WHERE status = 'NEW'
ORDER BY
date
UPDATE …
在交易中。
答案 4 :(得分:1)
存储过程是可行的方法。你需要看看交易。 Sql server就是为这种事而诞生的。
答案 5 :(得分:1)
是的,并且可能使用rowlock提示使其与其他线程隔离,例如
UPDATE
Jobs WITH (ROWLOCK, UPDLOCK, READPAST)
SET Status = 'WORKING'
WHERE JobID =
(SELECT Top 1 JobId FROM Jobs WHERE Status = 'NEW')
编辑:Quassnoi建议Rowlock会更好,但同样的想法适用于在一个查询中进行更新。