Den eneste bærbare måde at opnå overensstemmelse mellem rum og tags og sikre, at værelser aldrig returneres, efter at de er blevet slettet, er at låse dem med SELECT FOR UPDATE
.
Men i nogle systemer er låsning en bivirkning af samtidighedskontrol, og du opnår de samme resultater uden at angive FOR UPDATE
eksplicit.
For at løse dette problem skal tråd 1 SELECT id FROM rooms FOR UPDATE
, og derved forhindrer Tråd 2 i at slette fra rooms
indtil tråd 1 er færdig. Er det korrekt?
Dette afhænger af den samtidighedskontrol dit databasesystem bruger.
-
MyISAM
iMySQL
(og flere andre gamle systemer) låser hele tabellen under en forespørgsel. -
I
SQL Server
,SELECT
forespørgsler placerer delte låse på de poster / sider / tabeller, de har undersøgt, mensDML
forespørgsler placerer opdateringslåse (som senere bliver forfremmet til eksklusive eller degraderet til delte låse). Eksklusive låse er inkompatible med delte låse, så entenSELECT
ellerDELETE
forespørgslen låses, indtil en anden session forpligtes. -
I databaser, der bruger
MVCC
(somOracle
,PostgreSQL
,MySQL
medInnoDB
), enDML
query opretter en kopi af posten (på en eller anden måde), og generelt blokerer læsere ikke forfattere og omvendt. For disse databaser, enSELECT FOR UPDATE
ville være praktisk:det ville låse entenSELECT
ellerDELETE
forespørgsel indtil en anden session begår, ligesomSQL Server
gør.
Hvornår skal man bruge REPEATABLE_READ
transaktionsisolering versus READ_COMMITTED
med SELECT ... FOR UPDATE
?
Generelt REPEATABLE READ
forbyder ikke fantomrækker (rækker, der dukkede op eller forsvandt i en anden transaktion, i stedet for at blive ændret)
-
I
Oracle
og tidligerePostgreSQL
versioner,REPEATABLE READ
er faktisk et synonym forSERIALIZABLE
. Grundlæggende betyder det, at transaktionen ikke ser ændringer foretaget efter den er startet. Så i denne opsætning, den sidsteThread 1
forespørgslen vil returnere rummet, som om det aldrig er blevet slettet (hvilket måske er, hvad du ønskede). Hvis du ikke ønsker at vise rummene efter de er blevet slettet, skal du låse rækkerne medSELECT FOR UPDATE
-
I
InnoDB
,REPEATABLE READ
ogSERIALIZABLE
er forskellige ting:læsere iSERIALIZABLE
tilstand indstiller næste-tastlåse på de poster, de evaluerer, hvilket effektivt forhindrer den samtidigeDML
på dem. Så du behøver ikke enSELECT FOR UPDATE
i serialiserbar tilstand, men har brug for dem iREPEATABLE READ
ellerREAD COMMITED
.
Bemærk, at standarden for isolationstilstande foreskriver, at du ikke kan se visse særheder i dine forespørgsler, men ikke definerer hvordan (med låsning eller med MVCC
eller på anden måde).
Når jeg siger "du behøver ikke SELECT FOR UPDATE
" Jeg burde virkelig have tilføjet "på grund af bivirkninger af visse databasemotorimplementeringer".