Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Naruszenie ograniczenia UNIQUE KEY na INSERT WHERE COUNT(*) =0 w SQL Server 2005

Dlaczego to nie działa?

Uważam, że domyślnym zachowaniem SQL Server jest zwalnianie współdzielonych blokad, gdy tylko nie są już potrzebne. Twoje podzapytanie spowoduje krótkotrwałą współdzieloną blokadę (S) na stole, która zostanie zwolniona, gdy tylko podzapytanie się zakończy.

W tym momencie nic nie stoi na przeszkodzie, aby równoczesna transakcja wstawiła ten sam wiersz, który właśnie zweryfikowałeś, nie był obecny.

Jaką modyfikację muszę wprowadzić, aby nie było szansy na wyjątek z powodu naruszenia ograniczenia?

Dodanie HOLDLOCK wskazówka do podzapytania poinstruuje SQL Server, aby trzymał blokadę do czasu zakończenia transakcji. (W twoim przypadku jest to transakcja niejawna.) HOLDLOCK wskazówka jest odpowiednikiem SERIALIZABLE wskazówka, która sama w sobie jest odpowiednikiem poziomu izolacji transakcji, który można serializować, o którym mowa na liście „innych podejść”.

HOLDLOCK sama wskazówka wystarczyłaby, aby zachować blokadę S i uniemożliwić równoczesnej transakcji wstawienie wiersza, przed którym chronisz. Jednak prawdopodobnie zauważysz, że Twój unikalny błąd naruszenia klucza zostanie zastąpiony przez zakleszczenia, występujące z tą samą częstotliwością.

Jeśli zachowujesz tylko blokadę S na stole, rozważ wyścig między dwiema równoczesnymi próbami wstawienia tego samego wiersza, kontynuując w lockstep — obydwa udaje się uzyskać blokadę S na stole, ale żadnemu z nich nie uda się uzyskać wyłączności (X) zamek wymagany do wykonania wkładki.

Na szczęście istnieje inny typ blokady dla tego konkretnego scenariusza, zwany blokadą aktualizacji (U). Blokada U jest identyczna z blokadą S z następującą różnicą:podczas gdy wiele blokad S może być utrzymywanych jednocześnie na tym samym zasobie, tylko jedna blokada U może być jednocześnie utrzymywana. (Mówiąc inaczej, podczas gdy blokady S są ze sobą kompatybilne (tj. mogą współistnieć bez konfliktu), blokady U nie są ze sobą kompatybilne, ale mogą współistnieć z blokadami S; i dalej wzdłuż spektrum, blokady Exclusive (X) nie są kompatybilny z zamkami S lub U)

Możesz uaktualnić niejawną blokadę S w podzapytaniu do blokady U za pomocą UPDLOCK wskazówka.

Dwie równoczesne próby wstawienia tego samego wiersza do tabeli zostaną teraz zserializowane w początkowej instrukcji select, ponieważ ta uzyskuje (i utrzymuje) blokadę U, która nie jest kompatybilna z inną blokadą U z równoczesnej próby wstawienia.

Wartości NULL

Osobny problem może wynikać z faktu, że FieldC dopuszcza wartości NULL.

Jeśli ANSI_NULLS jest włączone (domyślnie), a następnie sprawdzanie równości FieldC=NULL zwróci false, nawet w przypadku, gdy FieldC ma wartość NULL (musisz użyć IS NULL operator do sprawdzania wartości null, gdy ANSI_NULLS jest włączony). Ponieważ FieldC dopuszcza wartość NULL, sprawdzenie duplikatów nie zadziała podczas wstawiania wartości NULL.

Aby poprawnie radzić sobie z wartościami null, musisz zmodyfikować podzapytanie EXISTS tak, aby używało IS NULL operator zamiast = gdy wstawiana jest wartość NULL. (Lub możesz zmienić tabelę, aby nie zezwalać na wartości NULL we wszystkich odpowiednich kolumnach.)

Zasoby dotyczące SQL Server Books Online

  • Wskazówki dotyczące blokowania
  • Matryca zgodności blokady
  • ANSI_NULLS


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. jak zapisać liczbę do funkcji słowa w serwerze sql

  2. Jak opróżnić bufor PRINT w TSQL?

  3. Podziel partycję na dwie w SQL Server (T-SQL)

  4. Unikalne ograniczenie w wielu kolumnach

  5. SQL Server - połącz wiersze w listę oddzieloną przecinkami