sql >> Databasteknik >  >> RDS >> Mysql

När ska man använda SELECT ... FÖR UPPDATERING?

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ån rooms tills tråd 1 är klar. Stämmer det?

Detta beror på den samtidighetskontroll som ditt databassystem använder.

  • MyISAM i MySQL (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, medan DML 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å antingen SELECT eller DELETE frågan låses tills en annan session commits.

  • I databaser som använder MVCC (som Oracle , PostgreSQL , MySQL med InnoDB ), en DML 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, en SELECT FOR UPDATE skulle vara praktiskt:det skulle låsa antingen SELECT eller DELETE fråga tills en annan session begår, precis som SQL Server gör.

När ska man använda REPEATABLE_READ transaktionsisolering kontra READ_COMMITTED med SELECT ... 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 tidigare PostgreSQL versioner, REPEATABLE READ är faktiskt en synonym för SERIALIZABLE . 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 sista Thread 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 med SELECT FOR UPDATE

  • I InnoDB , REPEATABLE READ och SERIALIZABLE är olika saker:läsare i SERIALIZABLE läge ställer in nästa knapplås på posterna de utvärderar, vilket effektivt förhindrar samtidig DML på dem. Så du behöver ingen SELECT FOR UPDATE i serialiserbart läge, men behöver dem i REPEATABLE READ eller READ 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".



  1. Hur kan jag skriva SQLite Real-värden till Java BigDecimal-värden?

  2. Omskrivning av frågor för att förbättra prestanda

  3. SQLite Like() Funktion med exempel

  4. Hur skickar jag en lista som en parameter i en lagrad procedur?