sql >> Database >  >> RDS >> Sqlserver

Schending van UNIQUE KEY-beperking op INSERT WHERE COUNT(*) =0 op SQL Server 2005

Waarom werkt dit niet?

Ik geloof dat het standaardgedrag van SQL Server is om gedeelde vergrendelingen vrij te geven zodra ze niet langer nodig zijn. Uw subquery resulteert in een kortstondige gedeelde (S) lock op de tafel, die wordt vrijgegeven zodra de subquery is voltooid.

Op dit moment is er niets dat een gelijktijdige transactie verhindert om de rij in te voegen waarvan u zojuist heeft geverifieerd dat deze niet aanwezig was.

Welke wijziging moet ik aanbrengen zodat er geen kans is op een uitzondering vanwege de schending van de beperking?

De HOLDLOCK . toevoegen hint naar uw subquery zal SQL Server instrueren om de vergrendeling vast te houden totdat de transactie is voltooid. (In uw geval is dit een impliciete transactie.) De HOLDLOCK hint is gelijk aan de SERIALIZABLE hint, die zelf gelijk is aan het serialiseerbare transactie-isolatieniveau waarnaar u verwijst in uw lijst met "andere benaderingen".

De HOLDLOCK een hint alleen zou voldoende zijn om de S-lock te behouden en te voorkomen dat een gelijktijdige transactie de rij invoegt waartegen u waakt. U zult echter waarschijnlijk merken dat uw unieke sleutelovertredingsfout wordt vervangen door deadlocks, die zich met dezelfde frequentie voordoen.

Als u alleen een S-lock op de tafel behoudt, overweeg dan een race tussen twee gelijktijdige pogingen om dezelfde rij in te voegen, waarbij u in lockstep verdergaat -- beide slagen erin een S-lock op de tafel te verwerven, maar geen van beide kan erin slagen de Exclusive te verwerven (X) slot vereist om het invoegen uit te voeren.

Gelukkig is er een ander type slot voor dit exacte scenario, het Update (U) slot. Het U-slot is identiek aan een S-slot met het volgende verschil:terwijl meerdere S-sloten tegelijkertijd op dezelfde bron kunnen worden gehouden, kan er slechts één U-slot tegelijk worden vastgehouden. (Anders gezegd, terwijl S-sloten compatibel met elkaar zijn (d.w.z. zonder conflict naast elkaar kunnen bestaan), zijn U-sloten niet compatibel met elkaar, maar kunnen ze naast S-sloten naast elkaar bestaan; en verder in het spectrum zijn exclusieve (X)-sloten niet compatibel met S- of U-sloten)

U kunt de impliciete S-lock op uw subquery upgraden naar een U-lock met behulp van de UPDLOCK hint.

Twee gelijktijdige pogingen om dezelfde rij in de tabel in te voegen, worden nu geserialiseerd bij de eerste select-instructie, omdat hiermee een U-lock wordt verkregen (en vastgehouden), die niet compatibel is met een ander U-lock van de gelijktijdige invoegpoging.

NULL-waarden

Een apart probleem kan ontstaan ​​door het feit dat FieldC NULL-waarden toestaat.

Als ANSI_NULLS is ingeschakeld (standaard) dan de gelijkheidscontrole FieldC=NULL zou false retourneren, zelfs in het geval waar FieldC NULL is (u moet de IS NULL gebruiken operator om te controleren op null wanneer ANSI_NULLS staat aan). Aangezien FieldC nullable is, werkt uw dubbele controle niet bij het invoegen van een NULL-waarde.

Om correct met nulls om te gaan, moet u uw EXISTS-subquery aanpassen om de IS NULL te gebruiken operator in plaats van = wanneer een waarde van NULL wordt ingevoegd. (Of u kunt de tabel wijzigen om NULL's in alle betrokken kolommen niet toe te staan.)

SQL Server Boeken Online Referenties

  • Hints voor vergrendelen
  • Compatibiliteitsmatrix vergrendelen
  • ANSI_NULLS


  1. Hoe kan ik een rij in een tabel BIJWERKEN of INVOEREN als deze niet bestaat?

  2. Hoe SESSION_CONTEXT() werkt in SQL Server

  3. Het laatste record in elke groep ophalen - MySQL

  4. ODP.NET Beheerde bibliotheek lost alias op, maar 32-bits bibliotheek wel