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ånroomstills tråd 1 är klar. Stämmer det?
Detta beror på den samtidighetskontroll som ditt databassystem använder.
-
MyISAMiMySQL(och flera andra gamla system) låser hela tabellen under en frågas varaktighet. -
I
SQL Server,SELECTfrågor placerar delade lås på de poster / sidor / tabeller de har undersökt, medanDMLfrå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å antingenSELECTellerDELETEfrågan låses tills en annan session commits. -
I databaser som använder
MVCC(somOracle,PostgreSQL,MySQLmedInnoDB), enDMLquery 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 UPDATEskulle vara praktiskt:det skulle låsa antingenSELECTellerDELETEfråga tills en annan session begår, precis somSQL Servergör.
När ska man använda
REPEATABLE_READtransaktionsisolering kontraREAD_COMMITTEDmedSELECT ... 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
Oracleoch tidigarePostgreSQLversioner,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 1query 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 READochSERIALIZABLEär olika saker:läsare iSERIALIZABLEläge ställer in nästa knapplås på posterna de utvärderar, vilket effektivt förhindrar samtidigDMLpå dem. Så du behöver ingenSELECT FOR UPDATEi serialiserbart läge, men behöver dem iREPEATABLE READellerREAD 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".