Przydatne może być przyjrzenie się, jak to zapytanie jest faktycznie wykonywane przez MySQL:
select * from tbl_codes where available = 1 order by rand() limit 1 for update
Spowoduje to odczytanie i posortowanie wszystkich wierszy pasujących do WHERE
warunek, wygeneruj losową liczbę za pomocą rand()
do wirtualnej kolumny dla każdego wiersza, posortuj wszystkie wiersze (w tabeli tymczasowej) na podstawie tej wirtualnej kolumny, a następnie zwróć wiersze do klienta z posortowanego zestawu do wartości LIMIT
zostanie osiągnięty (w tym przypadku tylko jeden). FOR UPDATE
wpływa na blokowanie wykonywane przez całą instrukcję podczas jej wykonywania i jako taka klauzula jest stosowana, gdy wiersze są odczytywane w InnoDB , nie gdy są zwracane do klienta.
Odkładając na bok oczywiste konsekwencje powyższego rozwiązania (to straszne), nigdy nie uzyskasz z tego rozsądnego zachowania blokowania.
Krótka odpowiedź:
- Wybierz żądany wiersz, używając
RAND()
lub dowolną inną strategię, aby znaleźćPRIMARY KEY
wartość tego wiersza. Np.:SELECT id FROM tbl_codes WHERE available = 1 ORDER BY rand() LIMIT 1
- Zablokuj żądany wiersz za pomocą jego
PRIMARY KEY
tylko. Np.:SELECT * FROM tbl_codes WHERE id = N
Mam nadzieję, że to pomoże.