Proszę, pomóż mi zrozumieć przypadek użycia SELECT ... FOR UPDATE
.
Pytanie 1 : Czy poniższy przykład jest dobrym przykładem, kiedy SELECT ... FOR UPDATE
należy stosować?
Dany:
- pokoje [id]
- tagi [identyfikator, nazwa]
- room_tags [room_id, tag_id]
- room_id i tag_id to klucze obce
Aplikacja chce wyświetlić wszystkie pokoje i ich tagi, ale musi rozróżnić pokoje bez tagów od tych, które zostały usunięte. Jeśli SELECT ... FOR UPDATE nie jest używany, może się zdarzyć:
- Początkowo:
- pokoje zawiera
[id = 1]
- tagi zawiera
[id = 1, name = 'cats']
- room_tags zawiera
[room_id = 1, tag_id = 1]
- pokoje zawiera
- Wątek 1:
SELECT id FROM rooms;
returns [id = 1]
- Wątek 2:
DELETE FROM room_tags WHERE room_id = 1;
- Wątek 2:
DELETE FROM rooms WHERE id = 1;
- Wątek 2: [zatwierdza transakcję]
- Wątek 1:
SELECT tags.name FROM room_tags, tags WHERE room_tags.tag_id = 1 AND tags.id = room_tags.tag_id;
- zwraca pustą listę
Teraz wątek 1 uważa, że pokój 1 nie ma tagów, ale w rzeczywistości pokój został usunięty. Aby rozwiązać ten problem, Wątek 1 powinien SELECT id FROM rooms FOR UPDATE
zapobiegać usuwaniu wątku 2 od rooms
momentu zakończenia Wątku 1. Czy to jest poprawne?
Pytanie 2 : Kiedy należy używać SERIALIZABLE
izolacji transakcji, a READ_COMMITTED
kiedy z SELECT ... FOR UPDATE
?
Odpowiedzi powinny być przenośne (nie specyficzne dla bazy danych). Jeśli to niemożliwe, wyjaśnij dlaczego.
REPEATABLE_READ
aREAD_COMMITTED
nawet opcje przenośne? Jedyne wyniki, które otrzymuję, dotyczą serwera MSSQLREAD COMMITTED
trybu nie definiuje, czy rzeczywiście zobaczysz rekordy zatwierdzone przez inną transakcję: zapewnia tylko, że nigdy nie zobaczysz niezatwierdzonych rekordów.select ... for update
Narooms
wciąż pozwalająroom_tags
być usunięte, ponieważ są osobne tabele. Czy chodziło Ci o pytanie, czyfor update
klauzula zapobiegnie usunięciomrooms
?Odpowiedzi:
Jedynym przenośnym sposobem na osiągnięcie spójności między pokojami i tagami oraz zapewnienie, że pokoje nigdy nie zostaną zwrócone po ich usunięciu, jest ich zablokowanie
SELECT FOR UPDATE
.Jednak w niektórych systemach blokowanie jest efektem ubocznym kontroli współbieżności i można osiągnąć te same wyniki bez
FOR UPDATE
jawnego określania .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
zapytań miejsce wspólne zamki na płytach / pages / Stoły mają badanych, natomiastDML
zamki zapytań miejsce aktualizacji (który później awansować do wyłącznej lub zdegradowany do wspólnych zamków). Wyłączne blokady są niekompatybilne z zamkami współdzielonymi, więc alboSELECT
alboDELETE
zapytanie zostanie zablokowana do momentu zatwierdzenia innej sesji.W bazach danych, których używanie
MVCC
(jakOracle
,PostgreSQL
,MySQL
zInnoDB
), ADML
kwerenda tworzy kopię rekordu (w jednym lub w inny sposób) i ogólnie czytelnicy nie blokować pisarzy i vice versa. W przypadku tych baz danychSELECT FOR UPDATE
przydałby się: blokowałby jednoSELECT
lubDELETE
zapytanie do momentu zatwierdzenia innej sesji, tak jak to sięSQL Server
dzieje.Generalnie
REPEATABLE READ
nie zabrania wierszy fantomowych (wierszy, które pojawiły się lub zniknęły w innej transakcji, zamiast być modyfikowane)We
Oracle
wcześniejszychPostgreSQL
wersjachREPEATABLE READ
jest w rzeczywistości synonimemSERIALIZABLE
. Zasadniczo oznacza to, że transakcja nie widzi zmian wprowadzonych po jej rozpoczęciu. Tak więc w tej konfiguracji ostatnieThread 1
zapytanie zwróci pokój tak, jakby nigdy nie został usunięty (co może być tym, czego chciałeś, ale nie musi). Jeśli nie chcesz pokazywać pokoi po ich usunięciu, powinieneś zablokować wiersze za pomocąSELECT FOR UPDATE
W
InnoDB
,REPEATABLE READ
aSERIALIZABLE
to dwie różne rzeczy: czytniki wSERIALIZABLE
zestawie trybu next-key zamki ewidencji one ocenić, co skutecznie zapobiega równoczesnaDML
na nich. Więc nie potrzebujeszSELECT FOR UPDATE
w trybie serializowalnym, ale potrzebujesz ich wREPEATABLE READ
lubREAD COMMITED
.Zauważ, że standard dotyczący trybów izolacji nakazuje, że nie widzisz pewnych dziwactw w zapytaniach, ale nie definiuje jak (z blokowaniem, z
MVCC
lub w inny sposób).Kiedy mówię „nie potrzebujesz
SELECT FOR UPDATE
”, naprawdę powinienem był dodać „z powodu skutków ubocznych implementacji niektórych silników bazodanowych”.źródło
SERIALIZABLE
powinno być używane, a kiedyREAD_COMMITTED
zSELECT ... FOR UPDATE
. Czy możesz zaktualizować swoją odpowiedź, aby odzwierciedlić to zaktualizowane pytanie?SELECT FOR UPDATE
w trybie serializowalnym", zInnoDB
. W przypadku innychMVCC
systemów te dwa są synonimami i potrzebujeszSELECT FOR UPDATE
.This depends on the concurrency control your database system is using
: Myślę, że rozdwajasz włosy. Wszystkie przypadki, które wymienisz poniżej, mówią, że pokój nie jest usuwany odSELECT
końca transakcji. Czy zatem odpowiedź nie powinna być po prostu zaYes
pomocą poniższych odnośników pomocniczych?Krótkie odpowiedzi:
P1: Tak.
P2: Nie ma znaczenia, którego używasz.
Długa odpowiedź:
select ... for update
Będzie (jak to wskazuje) wybrać niektóre wiersze, ale także zablokować je tak, jakby zostały już zaktualizowane przez bieżącej transakcji (lub jeśli aktualizacja tożsamość została wykonana). Dzięki temu możesz ponownie zaktualizować je w bieżącej transakcji, a następnie zatwierdzić, bez możliwości zmiany tych wierszy przez inną transakcję.Patrząc na to z innego punktu widzenia, wygląda na to, że następujące dwie instrukcje są wykonywane niepodzielnie:
Ponieważ wiersze, na które
my_condition
ma wpływ, są zablokowane, żadna inna transakcja nie może ich w żaden sposób modyfikować, dlatego poziom izolacji transakcji nie ma tutaj znaczenia.Należy również pamiętać, że poziom izolacji transakcji jest niezależny od blokowania: ustawienie innego poziomu izolacji nie pozwala na obejście blokowania i aktualizowanie wierszy w innej transakcji, które są zablokowane przez transakcję.
To, które poziomy izolacji transakcji gwarantują (na różnych poziomach), to spójność danych podczas trwania transakcji.
źródło
What transaction isolation levels do guarantee [...] is the consistency of data once transactions are completed.
błędnie oznacza, że poziomy izolacji nie wpływają na to, co dzieje się podczas transakcji. Zalecam zrewidowanie tej sekcji i przedstawienie bardziej szczegółowych informacji o tym, jak wpływają one na to, co widzisz (lub czego nie widzisz) podczas transakcji.