Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Нарушение на ограничението UNIQUE KEY на INSERT WHERE COUNT(*) =0 на SQL Server 2005

Защо това не работи?

Вярвам, че поведението по подразбиране на SQL Server е да освобождава споделени ключалки веднага щом те вече не са необходими. Вашата подзаявка ще доведе до краткотрайно споделено (S) заключване на таблицата, което ще бъде освободено веднага щом подзаявката завърши.

В този момент нищо не пречи на едновременна транзакция да вмъкне самия ред, който току-що потвърдихте, че не присъства.

Каква промяна трябва да направя, за да няма шанс за изключение поради нарушение на ограничението?

Добавяне на HOLDLOCK hint към вашата подзаявка ще инструктира SQL Server да задържи заключването, докато транзакцията бъде завършена. (Във вашия случай това е неявна транзакция.) HOLDLOCK hint е еквивалентен на SERIALIZABLE намек, който сам по себе си е еквивалентен на нивото на изолация на транзакциите, което може да се сериализира, което споменавате в списъка си с „други подходи“.

HOLDLOCK Самият намек би бил достатъчен за запазване на S заключването и предотвратяване на едновременна транзакция от вмъкване на реда, от който се пазите. Вероятно обаче ще откриете, че вашата уникална грешка при нарушение на ключа е заменена от блокиране, възникващо със същата честота.

Ако запазвате само S заключване на масата, помислете за надпревара между два едновременни опита за вмъкване на един и същ ред, продължавайки в lockstep - и двата успяват да придобият S заключване на масата, но нито един не може да успее да придобие Exclusive (X) необходимо заключване за изпълнение на вмъкването.

За щастие има друг тип заключване за този точен сценарий, наречен Актуализиране (U) заключване. U заключването е идентично на S заключване със следната разлика:докато множество S ключалки могат да се държат едновременно на един и същ ресурс, само една U заключване може да бъде задържана в даден момент. (Казано по друг начин, докато S ключалките са съвместими помежду си (т.е. могат да съществуват съвместно без конфликт), U ключалките не са съвместими една с друга, но могат да съществуват заедно с S ключалки; и по-нататък по спектъра, изключителните (X) брави не са съвместим с S или U ключалки)

Можете да надстроите имплицитното заключване S на вашата подзаявка до U заключване с помощта на UPDLOCK намек.

Два едновременни опита за вмъкване на един и същ ред в таблицата вече ще се сериализират в първоначалния оператор за избор, тъй като това придобива (и задържа) U заключване, което не е съвместимо с друго U заключване от едновременния опит за вмъкване.

NULL стойности

Отделен проблем може да възникне от факта, че FieldC позволява NULL стойности.

Ако ANSI_NULLS е включено (по подразбиране), тогава проверката за равенство FieldC=NULL ще върне false, дори в случай, когато FieldC е NULL (трябва да използвате IS NULL оператор за проверка за нула, когато ANSI_NULLS е включен). Тъй като FieldC е нула, вашата дублирана проверка няма да работи при вмъкване на стойност NULL.

За да се справите правилно с нулевите стойности, ще трябва да модифицирате подзаявката си EXISTS, за да използвате IS NULL оператор, а не = когато се вмъква стойност NULL. (Или можете да промените таблицата, за да забраните NULL във всички съответни колони.)

Онлайн справочници за SQL Server Books

  • Съвети за заключване
  • Матрица за съвместимост на заключване
  • 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. Как да изпълним SSIS пакет от .NET?

  2. Каква е разликата между char, nchar, varchar и nvarchar в SQL Server?

  3. COUNT() срещу COUNT_BIG() в SQL Server:Каква е разликата?

  4. Примери за преобразуване на „smalldatetime“ в „datetime“ в SQL Server (T-SQL)

  5. условно уникално ограничение