Jedynym przenośnym sposobem na osiągnięcie spójności między pokojami i tagami oraz upewnienie się, że pokoje nigdy nie zostaną zwrócone po ich usunięciu, jest zablokowanie ich za pomocą SELECT FOR UPDATE
.
Jednak w niektórych systemach blokowanie jest efektem ubocznym kontroli współbieżności i uzyskuje się te same wyniki bez określenia FOR UPDATE
wyraźnie.
Aby rozwiązać ten problem, wątek 1 powinien SELECT id FROM rooms FOR UPDATE
, zapobiegając w ten sposób usuwaniu wątku 2 z rooms
aż do zakończenia wątku 1. Czy to prawda?
Zależy to od kontroli współbieżności używanej przez system bazy danych.
-
MyISAM
wMySQL
(i kilka innych starych systemów) blokuje całą tabelę na czas trwania zapytania. -
W
SQL Server
,SELECT
zapytania umieszczają blokady współdzielone na przebadanych rekordach / stronach / tabelach, podczas gdyDML
kwerendy umieszczają blokady aktualizacji (które później są awansowane na blokady wyłączne lub zdegradowane do blokad współdzielonych). Blokady na wyłączność są niekompatybilne z blokadami współdzielonymi, więc alboSELECT
lubDELETE
zapytanie zostanie zablokowane do czasu zatwierdzenia kolejnej sesji. -
W bazach danych używających
MVCC
(jakOracle
,PostgreSQL
,MySQL
zInnoDB
),DML
zapytanie tworzy kopię rekordu (w taki czy inny sposób) i generalnie czytelnicy nie blokują autorów i odwrotnie. W przypadku tych baz danychSELECT FOR UPDATE
przydałoby się:zablokowałoby alboSELECT
lubDELETE
zapytanie, aż kolejna sesja zostanie zatwierdzona, tak jakSQL Server
tak.
Kiedy należy użyć REPEATABLE_READ
izolacja transakcji a READ_COMMITTED
z SELECT ... FOR UPDATE
?
Ogólnie REPEATABLE READ
nie zabrania wierszy fantomowych (wiersze, które pojawiły się lub zniknęły w innej transakcji, zamiast być modyfikowane)
-
W
Oracle
i wcześniejszePostgreSQL
wersje,REPEATABLE READ
jest właściwie synonimemSERIALIZABLE
. Zasadniczo oznacza to, że transakcja nie widzi zmian wprowadzonych po jej rozpoczęciu. Tak więc w tej konfiguracji ostatniThread 1
zapytanie zwróci pokój tak, jakby nigdy nie został usunięty (co może, ale nie musi, być tym, czego chciałeś). Jeśli nie chcesz pokazywać pokoi po ich usunięciu, powinieneś zablokować wiersze za pomocąSELECT FOR UPDATE
-
W
InnoDB
,REPEATABLE READ
iSERIALIZABLE
są różne rzeczy:czytniki wSERIALIZABLE
tryb ustawia blokady następnego klawisza na rekordach, które oceniają, skutecznie zapobiegając współbieżnemuDML
na nich. Więc nie potrzebujeszSELECT FOR UPDATE
w trybie serializowalnym, ale potrzebujesz ich wREPEATABLE READ
lubREAD COMMITED
.
Zwróć uwagę, że standard trybów izolacji nakazuje, że nie widzisz pewnych dziwactw w zapytaniach, ale nie definiuje, jak (z blokowaniem lub z MVCC
lub inaczej).
Kiedy mówię „nie potrzebujesz SELECT FOR UPDATE
„Naprawdę powinienem był dodać „ze względu na skutki uboczne implementacji określonego silnika bazy danych”.