Sybase: пытается заблокировать запись при выборе, чтобы другой абонент не получил такую ​​же - PullRequest
2 голосов
/ 25 февраля 2010

У меня есть простая таблица в Sybase, скажем, она выглядит следующим образом:

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

Я хочу получить следующую запись в порядке «entry_date» и немедленно обновить «in_use» до «Y», чтобы указать, что запись недоступна для следующего входящего запроса. Кикер в том, что если два выполнения пути пытаются выполнить запрос одновременно, я хочу, чтобы второй блок заблокировал, чтобы он не захватывал одну и ту же запись.

Проблема в том, что я обнаружил, что вы не можете выполнить «SELECT FOR UPDATE» в Sybase, если у вас есть предложение ORDER BY, поэтому следующий сохраненный процесс не может быть создан из-за следующей ошибки из-за предложения ORDER BY в select - "FOR UPDATE" неправильно указан при использовании курсора READ ONLY.

Есть ли лучший способ получить следующую запись, заблокировать ее и обновить все за один атомный шаг?


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 голосов
/ 25 февраля 2010

, так как вы выбираете только одну строку (TOP 1), почему бы просто не использовать стандартную подсказку блокировки и забыть курсор:

BEGIN TRANSACTION

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

UPDATE ....
WHERE pk=@PK

COMMIT

, если вам действительно нужно зацикливаться, Google CURSOR FREE LOOP

Какими способами можно заменить курсор?

Вы можете зацикливаться, выбирая следующий MIN (PK)> @ CurrentPk, используя подсказки блокировки на SELECT.

...