sql >> Database teknologi >  >> RDS >> Sqlserver

Overtrædelse af UNIQUE KEY-begrænsning på INSERT WHERE COUNT(*) =0 på SQL Server 2005

Hvorfor virker dette ikke?

Jeg tror, ​​at standardadfærden for SQL Server er at frigive delte låse, så snart de ikke længere er nødvendige. Din underforespørgsel vil resultere i en kortvarig delt (S) lås på bordet, som frigives, så snart underforespørgslen er fuldført.

På dette tidspunkt er der intet, der forhindrer en samtidig transaktion i at indsætte den række, du lige har bekræftet, ikke var til stede.

Hvilken ændring skal jeg foretage, så der ikke er nogen chance for en undtagelse på grund af overtrædelsen af ​​begrænsningen?

Tilføjelse af HOLDLOCK hint til din underforespørgsel vil instruere SQL Server til at holde på låsen, indtil transaktionen er gennemført. (I dit tilfælde er dette en implicit transaktion.) HOLDLOCK tip svarer til SERIALIZABLE hint, som i sig selv svarer til det serialiserbare transaktionsisoleringsniveau, som du henviser til i din liste over "andre tilgange".

HOLDLOCK tip alene ville være tilstrækkeligt til at bevare S-låsen og forhindre en samtidig transaktion i at indsætte den række, du beskytter dig imod. Du vil dog sandsynligvis finde din unikke nøglekrænkelsesfejl erstattet af deadlocks, der forekommer med samme hyppighed.

Hvis du kun beholder en S-lås på bordet, så overvej et kapløb mellem to samtidige forsøg på at indsætte den samme række, fortsæt i låsetrin - begge lykkes med at erhverve en S-lås på bordet, men ingen af ​​dem kan få succes med at erhverve den eksklusive (X) lås påkrævet for at udføre indsættelsen.

Heldigvis er der en anden låsetype til netop dette scenarie, kaldet Update (U) låsen. U-låsen er identisk med en S-lås med følgende forskel:Mens flere S-låse kan holdes samtidigt på den samme ressource, må der kun holdes én U-lås ad gangen. (Sagt på en anden måde, mens S-låse er kompatible med hinanden (dvs. kan eksistere uden konflikt), er U-låse ikke kompatible med hinanden, men kan eksistere side om side med S-låse; og længere hen ad spektret er Exclusive (X) låse ikke kompatibel med enten S- eller U-låse)

Du kan opgradere den implicitte S-lås på din underforespørgsel til en U-lås ved hjælp af UPDLOCK tip.

To samtidige forsøg på at indsætte den samme række i tabellen vil nu blive serialiseret ved den indledende select-sætning, da denne erhverver (og holder) en U-lås, som ikke er kompatibel med en anden U-lås fra det samtidige indsættelsesforsøg.

NULL-værdier

Et separat problem kan opstå som følge af, at FieldC tillader NULL-værdier.

Hvis ANSI_NULLS er slået til (standard), så er lighedskontrollen FieldC=NULL ville returnere falsk, selv i det tilfælde, hvor FieldC er NULL (du skal bruge IS NULL operatør for at tjekke for null, når ANSI_NULLS er tændt). Da FieldC er nullbar, vil din duplikatkontrol ikke fungere, når du indsætter en NULL-værdi.

For at håndtere nuller korrekt skal du ændre din EXISTS underforespørgsel til at bruge IS NULL operator i stedet for = når en værdi på NULL indsættes. (Eller du kan ændre tabellen til ikke at tillade NULL i alle de pågældende kolonner.)

SQL Server Books Online References

  • Låsetip
  • Lås kompatibilitetsmatrix
  • ANSI_NULLS


  1. 5 praktiske databasetips til begyndere

  2. Får Oracle PL/SQL serverens IP v4?

  3. Installation af PDO-drivere til PostgreSQL på Mac (ved hjælp af Zend til eclipse)

  4. mysqli::mysqli():(HY000/2002):Kan ikke oprette forbindelse til lokal MySQL-server gennem socket 'MySQL' (2)