【发布时间】:2009-02-22 07:57:03
【问题描述】:
我有一个存储过程,它选择了 1 条记录。可以从不同 PC 上的多个不同应用程序调用存储过程。想法是存储过程带回下一条需要处理的记录,如果两个应用程序同时调用存储过程,不应该带回相同的记录。我的查询如下,我正在尝试尽可能高效地编写查询(sql 2008)。能比这更高效吗?
CREATE PROCEDURE GetNextUnprocessedRecord
AS
BEGIN
SET NOCOUNT ON;
--ID of record we want to select back
DECLARE @iID BIGINT
-- Find the next processable record, and mark it as dispatched
-- Must be done in a transaction to ensure no other query can get
-- this record between the read and update
BEGIN TRAN
SELECT TOP 1
@iID = [ID]
FROM
--Don't read locked records, only lock the specific record
[MyRecords] WITH (READPAST, ROWLOCK)
WHERE
[Dispatched] is null
ORDER BY
[Received]
--Mark record as picked up for processing
UPDATE
[MyRecords]
SET
[Dispatched] = GETDATE()
WHERE
[ID] = @iID
COMMIT TRAN
--Select back the specific record
SELECT
[ID],
[Data]
FROM
[MyRecords] WITH (NOLOCK, READPAST)
WHERE
[ID] = @iID
END
【问题讨论】:
-
我不相信这个 TSQL 在事务上是安全的......
-
尝试在 SELECT 之后和 UPDATE 之前放置 WAITFOR DELAY '0:2:0',运行 SP 并从另一个连接执行相同的 SP ...
-
其实我错了! HOLDLOCK 与 MyRecords 表上的 REPEATABLEREAD 具有相同的效果。
-
默认情况下最好是安全的。否则,就会出现广泛的概念混乱。
-
我仍然认为您需要使事务 SERIALIZABLE 而不是 REPEATABLEREAD
标签: sql-server transactions locking