Jeśli chodzi o problemy ze współbieżnością, masz 'łatwe' sposób, aby zapobiec problemom ze współbieżnością w drugiej metodzie, wewnątrz transakcji wykonaj wybór w wierszu artykułów (For update
jest teraz niejawna). Żadne jednoczesne wstawianie tego samego artykułu nie będzie w stanie uzyskać tej samej blokady i będzie na Ciebie czekać.
Dzięki nowym domyślnym poziomom izolacji, nawet bez użycia poziomu serializacji w transakcji, nie zobaczysz żadnego równoczesnego wstawiania w tabeli głosowania do końca transakcji. Więc Twoja SUMA powinna pozostać spójna lub wyglądać na spójną . Ale jeśli równoczesna transakcja wstawi głos na ten sam artykuł i zatwierdzenie przed tobą (a ta druga nie widzi twojego wstawienia), ostatnia transakcja do zatwierdzenia nadpisze licznik i stracisz 1 głos. Więc wykonaj blokowanie wiersza w artykule, używając opcji wyboru przed (i oczywiście wykonuj swoją pracę w transakcji). Łatwo jest przetestować, otworzyć 2 interaktywne sesje na MySQL i rozpocząć transakcje za pomocą BEGIN.
Jeśli używasz wyzwalacza, domyślnie jesteś w transakcji. Ale myślę, że powinieneś wykonać również wybór w tabeli artykułów, aby utworzyć niejawną blokadę wiersza dla współbieżnych uruchomionych wyzwalaczy (trudniejsze do przetestowania).
- Nie zapomnij o usuwaniu wyzwalaczy.
- Nie zapomnij wyzwalaczy aktualizacji.
- Jeśli nie używasz wyzwalaczy i kodu pozostającego, zachowaj ostrożność, każde zapytanie wstawiania/usuwania/aktualizowania głosów powinno blokować wiersz w odpowiednim artykule przed transakcją. Nie jest trudno o jednym zapomnieć.
Ostatni punkt:wykonaj trudniejsze transakcje, przed rozpoczęciem transakcji użyj:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
W ten sposób nie potrzebujesz blokad wierszy w artykułach, MySQL wykryje, że potencjalny zapis w tym samym wierszu ma miejsce i zablokuje inne transakcje do momentu zakończenia. Ale nie używaj czegoś, co obliczyłeś na podstawie poprzedniego żądania . Zapytanie o aktualizację będzie czekać na zwolnienie blokady w artykułach, gdy blokada zostanie zwolniona przez pierwszą transakcję COMMIT
obliczanie SUM
należy zrobić ponownie, aby policzyć. Zapytanie o aktualizację powinno więc zawierać SUM
lub uzupełnij.
update articles set nb_votes=(SELECT count(*) from vote) where id=2;
I tutaj zobaczysz, że MySQL jest sprytny, wykryto zakleszczenie, jeśli dwie transakcje próbują to zrobić, podczas gdy wstawianie zostało wykonane w tym samym czasie. Na poziomach serializacji nie znalazłem sposobu na uzyskanie nieprawidłowej wartości za pomocą :
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
insert into vote (...
update articles set nb_votes=(
SELECT count(*) from vote where article_id=xx
) where id=XX;
COMMIT;
Ale przygotuj się na zerwanie transakcji, którą musisz powtórzyć.