2010-11-05 11 views
6

Mam jedną tabelę, która jest odczytywana w tym samym czasie przez różne wątki.Ignorowanie zablokowanego wiersza w zapytaniu MySQL

Każdy wątek musi wybrać 100 wierszy, wykonać niektóre zadania w każdym wierszu (niezwiązane z bazą danych), a następnie usunąć wybrany wiersz z tabeli.

wiersze są wybierane za pomocą tej kwerendy:

SELECT id FROM table_name FOR UPDATE; 

Moje pytanie brzmi: Jak mogę ignorować (lub pomiń) wiersze, które zostały wcześniej zablokowane za pomocą instrukcji SELECT w MySQL?

Odpowiedz

15

ja zazwyczaj utworzyć kolumnę PROCESS_ID który jest domyślny NULL i wtedy każdy wątek użyciu unikalnego identyfikatora wykonać następujące czynności:

UPDATE table_name SET process_id = #{process.id} WHERE process_id IS NULL LIMIT 100; 

SELECT id FROM table_name WHERE process_id = #{process.id} FOR UPDATE; 

To gwarantuje, że każdy wątek wybiera unikalny zestaw wierszy z tabeli.

Mam nadzieję, że to pomoże.

+1

+1 stosując limit to dobry pomysł –

+1

W tym przykładzie, jeśli skrypt nagle przerwany po pierwszej aktualizacji, w jaki sposób „oczyścić”. baza danych ze starych procesów? W przeciwnym razie te 100 wierszy nigdy by się nie zajął. –

+1

Dobre pytanie. Zwykle ustawiam tę samą kolumnę lub " stan "kolumna wskazująca pomyślne zakończenie (w ramach transakcji). Następnie, jeśli proces umiera, możesz ustawić parametr process_id dla nieistniejącego procesu z powrotem na NULL, aby inny proces mógł zostać przechwycony. Wolę prace crona w celu oczyszczenia, ale można również włączyć je w proces rozpoczynania nowego procesu. –

0

Mimo że nie jest to najlepsze rozwiązanie, ponieważ nie ma sposobu, aby zignorować zablokowane wiersze, wybieram losowy i próbuję uzyskać blokadę.

START TRANSACTION; 
SET @v1 =(SELECT myId FROM tests.table WHERE status is NULL LIMIT 1); 
SELECT * FROM tests.table WHERE [email protected] FOR UPDATE; #<- lock 

Ustawienie małego limitu czasu dla transakcji, jeśli ten wiersz jest zablokowany, transakcja jest przerywana, a ja próbuję innej. Jeśli zdobędę zamek, przetwarzam go. Jeśli (pech) ten wiersz był zablokowany, jest on przetwarzany, a blokada jest zwalniana przed upływem mojego czasu, a następnie wybieram wiersz, który został już "przetworzony"! Jednak sprawdzam pole ustawione przez moje procesy (np. Status): jeśli druga transakcja procesu zakończyła się pomyślnie, to pole mówi mi, że praca została już wykonana i nie przetwarzam ponownie tego wiersza.

Każde inne możliwe rozwiązanie bez transakcji (np. Ustawienie innego pola, jeśli wiersz nie ma statusu i ... itd.) Może z łatwością zapewnić warunki wyścigu i pominięte procesy (np. Jeden wątek nagle zginie, przydzielone dane są nadal oznaczone, podczas gdy wygaśnie transakcją;. ref skomentować here

Nadzieja pomaga