Wyszło to z tego pokrewnego pytania , w którym chciałem wiedzieć, jak zmusić dwie transakcje do sekwencyjnego wykonywania w trywialnym przypadku (gdzie obie operują tylko w jednym rzędzie). Otrzymałem odpowiedź - użyj SELECT ... FOR UPDATE
jako pierwszego wiersza obu transakcji - ale prowadzi to do problemu: jeśli pierwsza transakcja nigdy nie zostanie zatwierdzona lub wycofana, druga transakcja zostanie zablokowana na czas nieokreślony. innodb_lock_wait_timeout
Zmienna określa liczbę sekund, po którym klient próbuje zrobić drugą transakcję zostanie powiedziane „Niestety, spróbuj ponownie” ... ale o ile mogę powiedzieć, że będą ponownie próbują aż do następnego uruchomienia serwera. Więc:
- Z pewnością musi istnieć sposób na wymuszenie,
ROLLBACK
jeśli transakcja trwa wiecznie? Czy muszę uciekać się do używania demona do zabijania takich transakcji, a jeśli tak, to jak taki demon wyglądałby? - Jeśli połączenie zostanie przerwane w trakcie
wait_timeout
lub w trakcieinteractive_timeout
transakcji, czy transakcja zostanie wycofana? Czy istnieje sposób na przetestowanie tego z poziomu konsoli?
Wyjaśnienie : innodb_lock_wait_timeout
ustawia liczbę sekund, przez które transakcja będzie czekać na zwolnienie blokady przed poddaniem się; chcę wymusić zwolnienie blokady.
Aktualizacja 1 : Oto prosty przykład, który pokazuje, dlaczego innodb_lock_wait_timeout
nie wystarczy, aby pierwsza transakcja nie została zablokowana przez pierwszą:
START TRANSACTION;
SELECT SLEEP(55);
COMMIT;
Przy ustawieniu domyślnym innodb_lock_wait_timeout = 50
ta transakcja kończy się bez błędów po 55 sekundach. A jeśli dodasz znak UPDATE
przed SLEEP
wierszem, a następnie zainicjujesz drugą transakcję od innego klienta, który próbuje przejść do SELECT ... FOR UPDATE
tego samego wiersza, nastąpi przekroczenie limitu czasu drugiej transakcji, a nie tej, która zasnęła.
To, czego szukam, to sposób na wymuszenie końca spokojnego snu tej transakcji.
Aktualizacja 2 : W odpowiedzi na obawy hobodave dotyczące tego, jak realistyczny jest powyższy przykład, oto alternatywny scenariusz: DBA łączy się z serwerem na żywo i działa
START TRANSACTION
SELECT ... FOR UPDATE
gdzie druga linia blokuje wiersz, do którego aplikacja często zapisuje. Następnie DBA zostaje przerwane i odchodzi, zapominając o zakończeniu transakcji. Aplikacja zgrzyta, dopóki wiersz nie zostanie odblokowany. Chciałbym zminimalizować czas, w którym aplikacja utknęła w wyniku tego błędu.
ROLLBACK
pierwszą transakcję, jeśli jej wykonanie zajmuje więcej niż n
sekundy. Czy jest na to jakiś sposób?
MYSQL
nie mam konfiguracji, która zapobiegałaby temu scenariuszowi. Ponieważ nie można zaakceptować zawieszenia serwera z powodu nieodpowiedzialności klientów. Nie miałem trudności ze zrozumieniem twojego pytania, jest ono również bardzo istotne.