Sybase:尝试在select上锁定一条记录,这样另一个调用者就不会得到同一个

时间:2010-02-25 18:39:30

标签: sql sybase locking

我在Sybase中有一个简单的表,假设它看起来如下:

CREATE TABLE T
(
   name VARCHAR(10),
   entry_date datetime,
   in_use CHAR(1)
)

我希望根据“entry_date”的顺序获取下一个条目,并立即将“in_use”更新为“Y”,以指示该记录不可用于下一个查询。来说,如果两次执行,那就是路径尝试在我想要第二个阻塞的同时运行查询,因此它不会获取相同的记录。

问题是我发现如果你有一个ORDER BY子句,你不能在Sybase中执行“SELECT FOR UPDATE”,因此由于以下错误而无法创建以下存储过程,因为ORDER BY子句在select - 使用READ ONLY游标时错误地指定了“'FOR UPDATE'。

有没有更好的方法来获取下一条记录,锁定它,并在一个原子步骤中更新所有记录?


CREATE PROCEDURE dbo.sp_getnextrecord
@out1 varchar(10) out,
@out2 datetime out
AS
DECLARE @outOne varchar(10), @outTwo datetime

BEGIN TRANSACTION 

-- Here is the problem area Sybase does not like the
-- combination of 'ORDER BY' and 'FOR UPDATE' 
DECLARE myCursor CURSOR FOR
SELECT TOP 1 name, entry_date FROM T
WHERE in_use = 'N'
ORDER BY entry_Date asc FOR UPDATE OF in_use

OPEN myCursor

FETCH NEXT FROM myCursor
INTO @outOne, @outOne

-- Check @@FETCH_STATUS to see if there are any more rows to fetch.
WHILE @@FETCH_STATUS = 0
BEGIN

   UPDATE t SET IN_USE = 'Y' WHERE 
     name = @outOne AND entry_date = @outTwo

   SELECT @out1 = @outOne
   SELECT @out2 = @outTwo

   -- This is executed as long as the previous fetch succeeds.
   FETCH NEXT FROM myCursor
        INTO @outOne, @outTwo
END

CLOSE myCursor
DEALLOCATE myCursor

COMMIT TRANSACTION

1 个答案:

答案 0 :(得分:0)

因为你只选择一行(TOP 1),为什么不使用standard locking hint而忘记光标:

BEGIN TRANSACTION

SELECT @PK=ID FROM YourTable WITH (UPDLOCK, HOLDLOCK, READPAST) WHERE ...

UPDATE ....
WHERE pk=@PK

COMMIT

如果你真的需要循环,谷歌“CURSOR FREE LOOP”

What are the different ways to replace a cursor?

在使用SELECT上的锁定提示时,您可以通过选择下一个MIN(PK)> @CurrentPk来循环。