Jediný přenosný způsob, jak dosáhnout konzistence mezi místnostmi a štítky a zajistit, aby se místnosti po smazání nikdy nevrátily, je uzamknout je pomocí SELECT FOR UPDATE
.
V některých systémech je však zamykání vedlejším efektem kontroly souběžnosti a stejných výsledků dosáhnete bez zadání FOR UPDATE
explicitně.
K vyřešení tohoto problému by vlákno 1 mělo
SELECT id FROM rooms FOR UPDATE
, čímž zabrání vláknu 2 ve smazání zrooms
dokud nebude vlákno 1 hotové. Je to správně?
To závisí na kontrole souběžnosti, kterou váš databázový systém používá.
-
MyISAM
vMySQL
(a několik dalších starých systémů) uzamkne celou tabulku po dobu trvání dotazu. -
V
SQL Server
,SELECT
dotazy umísťují sdílené zámky na záznamy / stránky / tabulky, které zkoumaly, zatímcoDML
dotazy umísťují aktualizační zámky (které budou později povýšeny na exkluzivní nebo sníženy na sdílené zámky). Exkluzivní zámky jsou nekompatibilní se sdílenými zámky, takže buďSELECT
neboDELETE
dotaz se uzamkne, dokud nebude potvrzena další relace. -
V databázích, které používají
MVCC
(jakoOracle
,PostgreSQL
,MySQL
sInnoDB
),DML
dotaz vytvoří kopii záznamu (tak či onak) a obecně čtečky neblokují pisatele a naopak. Pro tyto databázeSELECT FOR UPDATE
by se hodilo:uzamklo by to buďSELECT
neboDELETE
dotazovat, dokud se nepotvrdí další relace, stejně jakoSQL Server
ano.
Kdy byste měli použít
REPEATABLE_READ
izolace transakce versusREAD_COMMITTED
pomocíSELECT ... FOR UPDATE
?
Obecně REPEATABLE READ
nezakazuje fiktivní řádky (řádky, které se objevily nebo zmizely v jiné transakci, místo aby byly upraveny)
-
V
Oracle
a dřívějšíPostgreSQL
verze,REPEATABLE READ
je ve skutečnosti synonymem proSERIALIZABLE
. V zásadě to znamená, že transakce po jejím spuštění neuvidí provedené změny. V tomto nastavení tedy posledníThread 1
dotaz vrátí místnost, jako by nikdy nebyla smazána (což může nebo nemusí být to, co jste chtěli). Pokud nechcete pokoje po smazání zobrazovat, měli byste řádky uzamknout pomocíSELECT FOR UPDATE
-
V
InnoDB
,REPEATABLE READ
aSERIALIZABLE
jsou různé věci:čtečky vSERIALIZABLE
režim nastavil zámky další klávesy na záznamech, které vyhodnocují, čímž účinně zabrání souběžnémuDML
na ně. Nepotřebujete tedySELECT FOR UPDATE
v serializovatelném režimu, ale potřebujete je vREPEATABLE READ
neboREAD COMMITED
.
Všimněte si, že standard pro režimy izolace předepisuje, že ve svých dotazech nevidíte určité zvláštnosti, ale nedefinuje jak (se zamykáním nebo pomocí MVCC
nebo jinak).
Když řeknu „nepotřebujete SELECT FOR UPDATE
" Opravdu jsem měl přidat "kvůli vedlejším účinkům určité implementace databázového stroje".