sql >> Databasteknik >  >> RDS >> Sqlserver

Brott mot UNIQUE KEY-begränsning på INSERT WHERE COUNT(*) =0 på SQL Server 2005

Varför fungerar inte det här?

Jag tror att standardbeteendet för SQL Server är att släppa delade lås så snart de inte längre behövs. Din underfråga kommer att resultera i ett kortvarigt delat (S) lås på bordet, som släpps så snart underfrågan är klar.

För närvarande finns det inget som hindrar en samtidig transaktion från att infoga just den rad som du just verifierade inte fanns.

Vilken modifiering behöver jag göra så att det inte finns någon chans att göra ett undantag på grund av begränsningsöverträdelsen?

Lägger till HOLDLOCK ledtråd till din underfråga kommer att instruera SQL Server att hålla fast vid låset tills transaktionen är slutförd. (I ditt fall är detta en implicit transaktion.) HOLDLOCK ledtråd motsvarar SERIALIZABLE ledtråd, som i sig motsvarar den serialiserbara transaktionsisoleringsnivån som du refererar till i din lista över "andra tillvägagångssätt".

HOLDLOCK enbart tips skulle vara tillräckligt för att behålla S-låset och förhindra att en samtidig transaktion infogar raden du skyddar dig mot. Däremot kommer du troligen att hitta ditt unika nyckelintrångsfel ersatt av dödlägen, som inträffar med samma frekvens.

Om du bara behåller ett S-lås på bordet, överväg ett lopp mellan två samtidiga försök att sätta in samma rad, fortsätt i låssteg -- båda lyckas få ett S-lås på bordet, men ingen av dem kan lyckas med att förvärva den exklusiva (X) lås krävs för att utföra infogningen.

Lyckligtvis finns det en annan låstyp för detta exakta scenario, kallat Update (U) lås. U-låset är identiskt med ett S-lås med följande skillnad:medan flera S-lås kan hållas samtidigt på samma resurs, kan endast ett U-lås hållas åt gången. (Sägt på ett annat sätt, även om S-lås är kompatibla med varandra (d.v.s. kan samexistera utan konflikt), är U-lås inte kompatibla med varandra, men kan samexistera tillsammans med S-lås; och längre fram i spektrumet är Exclusive (X) lås inte kompatibel med antingen S- eller U-lås)

Du kan uppgradera det implicita S-låset på din underfråga till ett U-lås med UPDLOCK ledtråd.

Två samtidiga försök att infoga samma rad i tabellen kommer nu att serialiseras vid den initiala select-satsen, eftersom detta förvärvar (och håller) ett U-lås, vilket inte är kompatibelt med ett annat U-lås från det samtidiga infogningsförsöket.

NULL-värden

Ett separat problem kan uppstå från det faktum att FieldC tillåter NULL-värden.

Om ANSI_NULLS är på (standard) så är likhetskontrollen FieldC=NULL skulle returnera false, även i fallet där FieldC är NULL (du måste använda IS NULL operatör för att kontrollera noll när ANSI_NULLS är på). Eftersom FieldC är nullbar kommer din dubblettkontroll inte att fungera när du infogar ett NULL-värde.

För att hantera nollor korrekt måste du ändra din EXISTS-underfråga för att använda IS NULL operator istället för = när ett värde på NULL infogas. (Eller så kan du ändra tabellen för att inte tillåta NULL i alla berörda kolumner.)

SQL Server Books Online References

  • Låstips
  • Lås kompatibilitetsmatris
  • ANSI_NULLS


  1. Oracle kopiera data till en annan tabell

  2. Pandas uppdatering sql

  3. Byt ut SQL-markörer med alternativ för att undvika prestandaproblem

  4. 3 sätt att få en lista över databaser i SQL Server (T-SQL)