W tabeli, gdzie każdy wiersz posiada licznik (tylko wartość całkowita), muszę dostać aktualną wartość i zwiększyć ją w tym samym czasie .
Skutecznie chcę to zrobić:
SELECT counter FROM table WHERE id=123
UPDATE table SET counter=counter+1 WHERE id=123
Ale robienie tego, ponieważ dwa zapytania nie są oczywiście bezpieczne dla wątków: wiele procesów wykonujących tę samą czynność (w tym samym wierszu) może otrzymać tę samą wartość licznika. Muszę im wszystkim być wyjątkowa, więc każdy proces będzie uzyskać rzeczywistą wartość prądu i zwiększać ją o jeden.
Mogę wymyślić konstrukcję, w której wdrażam ręczną blokadę na rząd, ale zastanawiam się, czy istnieje łatwiejszy sposób na zrobienie tego?
Odpowiedzi:
Instrukcje aktualizacji działają doskonale bez wcześniejszego wyboru! Ponieważ pojedyncze instrukcje są z definicji bezpieczne, nawet dwa zapytania UPDATE wykonywane w tym samym czasie spowodują dwukrotne zwiększenie wiersza.
Jeśli naprawdę chcesz wybrać wartość dla skryptu PHP, zrób coś z tym, a później chcesz zaktualizować tę dokładną wartość licznika, możesz wykonać następujące czynności:
To rozpoczyna nową transakcję, a następnie wybiera wiersze, które chcesz zaktualizować, i blokuje je wyłącznie. Następnie możesz je bezpiecznie aktualizować, nie martwiąc się o to, że inni klienci zmienią ich zawartość lub nawet uzyskają dostęp do zablokowanych wierszy. Wreszcie musisz zatwierdzić zmiany.
Powinieneś także przeczytać coś o poziomach izolacji . Prawdopodobnie nie chcesz wartości takiej
READ UNCOMMITTED
jak poziom izolacji. Wszystko inne powinno być w porządku w tym przypadku użycia.źródło
UPDATE table SET counter = counter + 1
jest wystarczająco atomowy? Czy nadal potrzebujesz otaczających go wyciągów z transakcji?FOR UPDATE
transakcji oraz transakcji, wybrana wartość może być inna niż ta, która została użyta w zapytaniu aktualizacyjnym. Moja kombinacja zapytań blokuje wiersz natychmiast po wybraniu wartości i dlatego zapewnia, że ta dokładna wartość licznika zostanie użyta w zapytaniu o aktualizację.