sql >> Database teknologi >  >> RDS >> Oracle

Forhindrer SELECT FOR UPDATE, at andre forbindelser indsættes, når rækken ikke er til stede?

MySQL

VÆLG ... TIL OPDATERING med OPDATERING

Ved at bruge transaktioner med InnoDB (auto-commit slået fra), en SELECT ... FOR UPDATE tillader en session midlertidigt at låse en bestemt post (eller poster), så ingen anden session kan opdatere den. Derefter, inden for den samme transaktion, kan sessionen faktisk udføre en UPDATE på samme registrering og begå eller rulle transaktionen tilbage. Dette vil give dig mulighed for at låse posten, så ingen anden session kan opdatere den, mens du måske laver en anden forretningslogik.

Dette opnås med låsning. InnoDB bruger indekser til at låse poster, så det virker nemt at låse en eksisterende post – du skal blot låse indekset for den post.

VÆLG ... TIL OPDATERING med INSERT

Men for at bruge SELECT ... FOR UPDATE med INSERT , hvordan låser man et indeks for en post, der ikke eksisterer endnu? Hvis du bruger standardisolationsniveauet REPEATABLE READ , vil InnoDB også bruge gap låse. Så længe du kender id (eller endda række af id'er) for at låse, så kan InnoDB låse hullet, så ingen anden post kan indsættes i det mellemrum, før vi er færdige med det.

Hvis dit id kolonne var en auto-increment kolonne, derefter SELECT ... FOR UPDATE med INSERT INTO ville være problematisk, fordi du ikke ville vide, hvad det nye id er var indtil du indsatte den. Men da du kender id som du ønsker at indsætte, SELECT ... FOR UPDATE med INSERT vil virke.

ADVARSEL

På standard isolationsniveau, SELECT ... FOR UPDATE på en ikke-eksisterende post ikke blokere andre transaktioner. Så hvis to transaktioner begge udfører en SELECT ... FOR UPDATE på den samme ikke-eksisterende indekspost, får de begge låsen, og ingen af ​​transaktionerne vil være i stand til at opdatere posten. Faktisk, hvis de prøver, vil et dødvande blive opdaget.

Derfor, hvis du ikke ønsker at håndtere et dødvande, kan du bare gøre følgende:

INDSÆT I ...

Start en transaktion, og udfør INSERT . Lav din forretningslogik, og forpligt eller fortæl transaktionen. Så snart du gør INSERT på det ikke-eksisterende postindeks på den første transaktion, blokeres alle andre transaktioner, hvis de forsøger at INSERT en post med det samme unikke indeks. Hvis den anden transaktion forsøger at indsætte en post med det samme indeks efter den første transaktion begår indsættelsen, vil den få en "duplicate key"-fejl. Håndter i overensstemmelse hermed.

VÆLG ... LÅS I DELETILSTAND

Hvis du vælger med LOCK IN SHARE MODE før INSERT , hvis en tidligere transaktion har indsat denne post, men endnu ikke er begået, skal SELECT ... LOCK IN SHARE MODE vil blokere, indtil den forrige transaktion er gennemført.

Så for at reducere risikoen for duplikerede nøglefejl, især hvis du holder låsene i et stykke tid, mens du udfører forretningslogik, før du begår dem eller ruller dem tilbage:

  1. SELECT bar FROM FooBar WHERE foo = ? LOCK FOR UPDATE
  2. Hvis ingen poster returneres, så
  3. INSERT INTO FooBar (foo, bar) VALUES (?, ?)


  1. EEE MMM dd TT:mm:ss ZZZ åååå datoformat til java.sql.Date

  2. Vigtig PostgreSQL-overvågning - del 3

  3. pip install mysqlclient returnerer fatal fejl C1083:Kan ikke åbne fil:'mysql.h':Ingen sådan fil eller mappe

  4. MySQL:Sorter GROUP_CONCAT-værdier