sql >> Databasteknik >  >> RDS >> Oracle

Förhindrar SELECT FOR UPDATE att andra anslutningar infogas när raden inte finns?

MySQL

VÄLJ ... FÖR UPPDATERING med UPPDATERING

Genom att använda transaktioner med InnoDB (auto-commit avstängd), en SELECT ... FOR UPDATE tillåter en session att tillfälligt låsa en viss post (eller poster) så att ingen annan session kan uppdatera den. Sedan, inom samma transaktion, kan sessionen faktiskt utföra en UPDATE på samma post och begå eller återställa transaktionen. Detta skulle tillåta dig att låsa ned posten så att ingen annan session kan uppdatera den medan du kanske gör någon annan affärslogik.

Detta görs med låsning. InnoDB använder index för att låsa poster, så det verkar enkelt att låsa en befintlig post – lås helt enkelt indexet för den posten.

VÄLJ ... FÖR UPPDATERING med INSERT

Men för att använda SELECT ... FOR UPDATE med INSERT , hur låser man ett index för en post som inte finns ännu? Om du använder standardisoleringsnivån REPEATABLE READ , kommer InnoDB också att använda gap lås. Så länge du känner till id (eller till och med ett antal id) för att låsa, då kan InnoDB låsa gapet så att ingen annan post kan infogas i den luckan förrän vi är klara med den.

Om ditt id kolumnen var en kolumn för automatisk ökning, sedan SELECT ... FOR UPDATE med INSERT INTO skulle vara problematiskt eftersom du inte skulle veta vad det nya id är var tills du satte in den. Men eftersom du känner till id som du vill infoga, SELECT ... FOR UPDATE med INSERT kommer att fungera.

VARNING

På standardisoleringsnivån, SELECT ... FOR UPDATE på en icke-existerande post inte blockera andra transaktioner. Så om två transaktioner båda gör en SELECT ... FOR UPDATE på samma obefintliga indexpost får de båda låset, och ingen av transaktionerna kommer att kunna uppdatera posten. Faktum är att om de försöker, kommer ett dödläge att upptäckas.

Därför, om du inte vill hantera ett dödläge, kan du bara göra följande:

INSERT I ...

Starta en transaktion och utför INSERT . Gör din affärslogik och antingen begå eller återställa transaktionen. Så snart du gör INSERT på det obefintliga postindexet på den första transaktionen, blockeras alla andra transaktioner om de försöker INSERT en post med samma unika index. Om den andra transaktionen försöker infoga en post med samma index efter att den första transaktionen genomfört infogningen, kommer den att få ett "duplicerat nyckel"-fel. Hantera därefter.

VÄLJ ... LÅS I DELNINGSLÄGE

Om du väljer med LOCK IN SHARE MODE före INSERT , om en tidigare transaktion har infogat den posten men inte har genomförts ännu, SELECT ... LOCK IN SHARE MODE blockeras tills den föregående transaktionen har slutförts.

Så för att minska risken för duplicerade nyckelfel, särskilt om du håller låsen ett tag medan du utför affärslogik innan du begår dem eller rullar tillbaka dem:

  1. SELECT bar FROM FooBar WHERE foo = ? LOCK FOR UPDATE
  2. Om inga poster returneras, då
  3. INSERT INTO FooBar (foo, bar) VALUES (?, ?)


  1. Hur man kör Oracle sql-skript med java-kod

  2. 4 tips för att köra SQL Server Diagnostics

  3. Full förståelse för PDO ATTR_PERSISTENT

  4. SQL-fråga med flera värden i en cell