Jedno takie zdanie działa tak samo z MyISAM lub InnoDB, z transakcją lub z autocommit = ON. Blokuje wystarczającą liczbę zapytań, blokując w ten sposób inne połączenie. Po zakończeniu drugie połączenie będzie kontynuowane. We wszystkich przypadkach kolumna jest wkrótce zmniejszana o 11.
Trzeci użytkownik może zobaczyć wartość zmniejszoną o 0 lub 4 lub 7 lub 11. „Bardzo dokładny czas” nie jest tak naprawdę możliwy, ponieważ w pewnym momencie wykonywania każdej instrukcji sprawdzana / ustawiana jest blokada jednowątkowa . Oznacza to, że będą one serializowane, tak szybko, że nie będzie można ich zobaczyć.
InnoDB blokuje tylko wiersze, a nie tabele. (OK, instrukcja DDL robi odważniejsze blokady).
Bardziej interesująca jest transakcja, która modyfikuje dwie rzeczy lub zajmuje zauważalnie dużo czasu:
Przypadek zamiaru: Pojedynczy element, ale wymaga czasu:
BEGIN;
SELECT something;
think about it for a while
UPDATE that something;
COMMIT;
Wybierz należy zapisać w ten sposób:
SELECT something FOR UPDATE;
Mówi to innym połączeniom: „Zamierzam zaktualizować wiersz; proszę, nie zadzieraj mi”. (Przytaczam ten przykład, ponieważ wielu początkujących tęskni za tą subtelnością).
Przypadek zakleszczenia: Bałagan z 2 rzeczami:
BEGIN; -- in one connection
UPDATE thing_1;
UPDATE thing_2;
COMMIT;
BEGIN; -- in another connection, at the "exact same time"
UPDATE thing_2;
UPDATE thing_1;
COMMIT;
Jest to klasyczny przykład impasu - każdy chwyta jedną rzecz, a następnie sięga po drugą. Oczywiście nie można tego zrobić. Jedna transakcja zostaje zabita; drugi kończy się. Dlatego musisz sprawdzić , czy nie ma błędów, aby je odkryć.
Normalną reakcją na impas jest odtworzenie całej nieudanej transakcji. Do tego czasu drugie połączenie nie będzie zakłócać i powinno działać bezproblemowo. (OK, kolejne połączenie może spowodować kolejny impas).
Przypadek opóźnienia: jeśli dwa połączenia chwytają wiele rzeczy w tej samej kolejności, jedno może zostać opóźnione do momentu zakończenia drugiego. Aby nie „czekać wiecznie”, domyślnie jest 50 sekund innodb_lock_wait_timeout
. Twoja para prostych UPDATEs
jest w rzeczywistości przykładem tego przypadku. Kończymy szybko; drugi jest zablokowany do pierwszego końca.
Zwróć uwagę, w jaki sposób Zakleszczenie (w niektórych przypadkach) można przekształcić w Opóźnienie poprzez konsekwentne porządkowanie rzeczy, których dotykasz.
autocommit = 1: Przy tym ustawieniu i bez wywoływania BEGIN
każda instrukcja działa skutecznie:
BEGIN;
your statement
COMMIT;
autocommit = 0: To jest problem z oczekiwaniem na wystąpienie. Podczas wykonywania zapytania dotyczącego zapisu BEGIN
jest generowane niejawnie. Jednak Twoim obowiązkiem jest ostatecznie wydać COMMIT
. Jeśli tego nie zrobisz, będziesz się zastanawiać, dlaczego twój system się zawiesił. (Kolejny typowy błąd dla początkujących.) Moja rada: „Nigdy nie używaj =0
”.