Pesymistyczne blokowanie wierszy do odczytu w bazie danych MySQL

Ostatnio natknąłem się na problem kiedy rekord w bazie danych był edytowany w tym samym czasie przez kilka procesów. Pisząc procesy mam na myśli skrypty, które uruchamiane mogą być w dowolnej chwili i trwać (wykonywać się) przez różny okres czasu choć  w tym przypadku raczej bardzo krótki.

W przypadku kiedy dwa procesy modyfikują rekord w tym samym czasie to zazwyczaj zmiany wprowadzone przez pierwszy proces są nadpisywane przez ten drugi, co oczywiście jest niepożądane. Dzieje się tak dlatego ponieważ drugi proces odczytuje zawartość rekordu zanim pierwszy proces zapisze swoje zmiany. Jest to tak zwana opcja „ostatni wygrywa”.

Rozwiązaniem problemu jest zablokowanie wiersza do odczytu poprzez zapytanie

SELECT * FROM `testlock` FOR UPDATE

zapytanie to blokuje dany wiersz i wszystkie powiązane z nim poprzez indeksy wiersze. Jest to rodzaj blokowania pesymistycznego w którym rekord blokowany jest od momentu odczytania danych do momentu zapisania zmodyfikowanych danych do bazy.

Blokada ta obsługiwana jest w MySQL tylko przez silnik InnoDB. Zapytanie musi być wykonane w transakcji a blokada z wiersza jest zdejmowana kiedy transakcja jest zatwierdzona (commited) lub wycofana (rolled back).

Uwaga

Nie jest to dobre podejście do sprawy jeśli chcemy rozwiązać problem edycji tego samego artykułu przez dwóch redaktorów. Tam powinno to wyglądać nieco inaczej. Przede wszystkim redaktor, który zaczyna edycję jako drugi powinien zostać poinformowany, że artykuł jest już przez kogoś edytowany i że powinien poczekać, ewentualnie można wprowadzić edycję live np. taką jak mamy w Google Docs.

Przydatne linki