Det enda bärbara sättet att uppnå överensstämmelse mellan rum och taggar och se till att rum aldrig returneras efter att de har tagits bort är att låsa dem med SELECT FOR UPDATE
.
Men i vissa system är låsning en bieffekt av samtidighetskontroll, och du uppnår samma resultat utan att specificera FOR UPDATE
uttryckligen.
För att lösa detta problem bör tråd 1
SELECT id FROM rooms FOR UPDATE
, vilket förhindrar att tråd 2 raderas frånrooms
tills tråd 1 är klar. Stämmer det?
Detta beror på den samtidighetskontroll som ditt databassystem använder.
-
MyISAM
iMySQL
(och flera andra gamla system) låser hela tabellen under en frågas varaktighet. -
I
SQL Server
,SELECT
frågor placerar delade lås på de poster / sidor / tabeller de har undersökt, medanDML
frågor placerar uppdateringslås (som senare flyttas upp till exklusiva eller nedgraderas till delade lås). Exklusiva lås är inkompatibla med delade lås, så antingenSELECT
ellerDELETE
frågan låses tills en annan session commits. -
I databaser som använder
MVCC
(somOracle
,PostgreSQL
,MySQL
medInnoDB
), enDML
query skapar en kopia av posten (på ett eller annat sätt) och i allmänhet blockerar inte läsare skribenter och vice versa. För dessa databaser, enSELECT FOR UPDATE
skulle vara praktiskt:det skulle låsa antingenSELECT
ellerDELETE
fråga tills en annan session begår, precis somSQL Server
gör.
När ska man använda
REPEATABLE_READ
transaktionsisolering kontraREAD_COMMITTED
medSELECT ... FOR UPDATE
?
I allmänhet REPEATABLE READ
förbjuder inte fantomrader (rader som dök upp eller försvann i en annan transaktion, snarare än att ändras)
-
I
Oracle
och tidigarePostgreSQL
versioner,REPEATABLE READ
är faktiskt en synonym förSERIALIZABLE
. I grund och botten innebär detta att transaktionen inte ser ändringar som görs efter att den har startat. Så i den här inställningen, den sistaThread 1
query kommer att returnera rummet som om det aldrig har tagits bort (vilket kanske inte är vad du ville ha). Om du inte vill visa rummen efter att de har tagits bort bör du låsa raderna medSELECT FOR UPDATE
-
I
InnoDB
,REPEATABLE READ
ochSERIALIZABLE
är olika saker:läsare iSERIALIZABLE
läge ställer in nästa knapplås på posterna de utvärderar, vilket effektivt förhindrar samtidigDML
på dem. Så du behöver ingenSELECT FOR UPDATE
i serialiserbart läge, men behöver dem iREPEATABLE READ
ellerREAD COMMITED
.
Observera att standarden för isoleringslägen föreskriver att du inte ser vissa egenheter i dina frågor men inte definierar hur (med låsning eller med MVCC
eller på annat sätt).
När jag säger "du behöver inte SELECT FOR UPDATE
" Jag borde verkligen ha lagt till "på grund av biverkningar av viss databasmotorimplementering".