2010-02-19 30 views
5

To jest zbyt uproszczone wyjaśnienie, nad czym pracuję.
Mam tabelę z kolumną statusu. Wiele instancji aplikacji spowoduje pobranie zawartości pierwszego wiersza o statusie NEW, zaktualizowanie statusu do WORKING, a następnie przejście do pracy nad zawartością.
Łatwo to zrobić z dwoma wywołania bazy danych; najpierw SELECT, następnie UPDATE. Ale chcę zrobić to wszystko w jednym wywołaniu, aby inna instancja aplikacji nie ciągnęła tego samego wiersza. Coś w rodzaju rzeczy typu SELECT_AND_UPDATE.Czy mogę wybrać i aktualizować w tym samym czasie?

Czy procedura składowana jest najlepszym rozwiązaniem?

Odpowiedz

2

Brzmi jak scenariusz przetwarzania kolejki, w którym chcesz tylko jeden proces, aby odebrać dany rekord.

Jeśli tak jest, spojrzeć na odpowiedź ja dostarczonych wcześniej dzisiaj, który opisuje, jak wdrożyć tę logikę za pomocą transakcji w połączeniu z UPDLOCK i READPAST podpowiedzi tabela: Row locks - manually using them

Najlepszy pochłonięty sproc .

Nie jestem pewien, czy właśnie tego chcesz, więc nie głosowałem, aby zamknąć jako duplikat.

+0

To jest to, czego potrzebowałem. Dzięki wielkie. –

1

Niezupełnie, ale można następnie SELECT ... WITH (UPDLOCK), a następnie UPDATE... Jest to tak dobre, jak operacja atomowa, ponieważ informuje bazę danych, że zamierzasz zaktualizować to, co wcześniej wybrałeś, aby zablokować te wiersze, zapobiegając kolizjom z innymi klientami. Pod Oracle i innymi bazami danych (MySQL, myślę), składnia jest SELECT ... FOR UPDATE.

Uwaga: Myślę, że musisz upewnić się, że dwie transakcje mają miejsce w ramach transakcji, aby działała.

+0

nie powinno to być ... Z UPDLOCK dla serwera Sql.Bądź też ostrożny, ponieważ podpowiedź UPDLOCK oznacza, że ​​blokady są przechowywane przeciwko twoim danym, co w długotrwałej transakcji może spowodować rywalizację z innymi transakcjami. –

+0

@Jeff: Tak, ale z jego opisu, tego właśnie chciał. Rzeczywiście musisz zachować ostrożność przy długich transakcjach, ale jest to jedyny sposób, w jaki znam zachowanie atomowe typu "czytaj, pisz". – jkp

8

Można użyć instrukcji 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 
+0

Uwaga: wymaga to programu SQL Server 2005 lub nowszego. – AakashM

+0

Wierzyłem, że autor chciał wykonać dodatkową pracę w ramach transakcji, jednak nic w pytaniu tego nie potwierdza. Więc +1. – Quassnoi

+0

BTW, nie "DOŁĄCZ" tutaj, wystarczy "CTE". – Quassnoi

1

powinien zrobić trzy rzeczy tutaj:

  1. zablokować wiersz pracujesz na
  2. Upewnij się, że ten i tylko ten wiersz jest zablokowany
  3. Nie czekaj na zablokowany rekordy: zamiast tego przejdź do następnych.

Aby to zrobić, wystarczy wydać to:

SELECT TOP 1 * 
FROM mytable (ROWLOCK, UPDLOCK, READPAST) 
WHERE status = 'NEW' 
ORDER BY 
     date 

UPDATE … 

obrębie transakcji.

1

Procedura przechowywana jest drogą do zrobienia. Musisz spojrzeć na transakcje. Serwer Sql narodził się z tego powodu.

1

Tak, i może użyć podpowiedzi typu "rowlock", aby zachować ją odizolowaną od innych wątków, np.

UPDATE 
Jobs WITH (ROWLOCK, UPDLOCK, READPAST) 
SET Status = 'WORKING' 
WHERE JobID = 
(SELECT Top 1 JobId FROM Jobs WHERE Status = 'NEW') 

EDIT: dulka będzie lepiej jak sugeruje Quassnoi, ale sama idea dotyczy zrobić aktualizację w jednym zapytaniu.

+0

czy wskazówki nie pojawią się w SELECT? –

+0

Nie wydaje mi się, żeby to miało znaczenie, ponieważ w grze jest tylko jeden wiersz i jest w jednym komunikacie. – Turnkey

Powiązane problemy