2012-10-06 16 views
9

Chcę, aby równoległe transakcje wybierały wiersz z tabeli, oznaczając go jako "brudny", aby inne transakcje nie mogły go wybrać, a następnie wykonując resztę transakcja.Minimalny przykład użycia select ... do aktualizacji w celu odizolowania wierszy

Miałem problemy z wykorzystaniem select... for update do tego celu, ponieważ druga transakcja dotyczy tego samego. Podaj minimalny przykład różnych transakcji, aby wybrać różne wiersze.

Moje dane to:

mysql> select * from SolrCoresPreallocated; 
+----+-------------+-----+-----+ 
| id | used_status | sid | cid | 
+----+-------------+-----+-----+ 
| 1 |   0 | 0 | 400 | 
| 2 |   0 | 0 | 401 | 
| 3 |   0 | 0 | 402 | 
| 4 |   0 | 0 | 403 | 
| 5 |   0 | 0 | 404 | 
| 6 |   0 | 0 | 405 | 
+----+-------------+-----+-----+ 
6 rows in set (0.00 sec) 

I to rzeczy nie działa zgodnie z oczekiwaniami:

mysql> begin; 
Query OK, 0 rows affected (0.00 sec) 

mysql> select * from SolrCoresPreallocated order by id limit 1 for update; 
+----+-------------+-----+-----+ 
| id | used_status | sid | cid | 
+----+-------------+-----+-----+ 
| 1 |   0 | 0 | 400 | 
+----+-------------+-----+-----+ 
1 row in set (0.00 sec) 

...set the used_status to 1 
...perform the rest of the operations 

... jako drugi transakcji naprzód

mysql> begin; 
Query OK, 0 rows affected (0.00 sec) 

mysql> select * from SolrCoresPreallocated order by id limit 1 for update; 
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 
mysql> rollback; 
Query OK, 0 rows affected (0.00 sec) 
+0

Co dokładnie robi, czego się nie spodziewałeś? –

+0

włączyło to również – aitchnyu

Odpowiedz

7

SELECT ... FOR UPDATE blokuje wiersz (s) w trybie wyłączności, co oznacza, że ​​drugi wybór nie może trwać, dopóki pierwszy nie zostanie skompletowany ted lub wycofany. Dzieje się tak, ponieważ na wynik drugiego selekcji może wpłynąć zawartość zablokowanego wiersza, więc należy uzyskać blokadę odczytu wiersza, aby sprawdzić.

Jeśli utworzysz na przykład id, możesz zrobić;

select * from SolrCoresPreallocated where id=1 for update; 

w pierwszej transakcji;

select * from SolrCoresPreallocated where id=2 for update; 

w drugim niezależnie, ponieważ unikalny indeks pozwala drugiemu wybrać znajdujący się prawidłowy wiersz bez blokowania odczytu pierwszego.

EDYCJA: Aby uzyskać "darmowy" wiersz tak szybko, jak to możliwe, jedynym sposobem jest wykonanie dwóch transakcji;

  • BEGIN/WYBIERZ AKTUALIZACJĘ/AKTUALIZACJĘ do zajętości/COMMIT, aby uzyskać wiersz.
  • BEGIN/< wiersz przetwarzania>/UPDATE, aby zwolnić/ZAPROGRAMOWAĆ, aby przetworzyć wiersz i zwolnić go.

To oznacza, że ​​może być konieczne w przypadku działań kompensacyjnych proces nie powiedzie się i wycofuje transakcję, która aktualizuje wiersz wolny, ale ponieważ MySQL (lub standardowego SQL dla tej sprawy) nie ma pojęcia "uzyskaj kolejny odblokowany wiersz", nie masz wielu opcji.

+0

Ale muszę wybrać ** następny ** wolny wiersz; Nie mogę zapytać w ten sposób, nawet jeśli działa – aitchnyu

+0

@aitchnyu Dodano edycję do odpowiedzi. –

Powiązane problemy