Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Vi phạm ràng buộc UNIQUE KEY trên INSERT WHERE COUNT (*) =0 trên SQL Server 2005

Tại sao điều này không hoạt động?

Tôi tin rằng hành vi mặc định của SQL Server là phát hành các khóa chia sẻ ngay khi chúng không còn cần thiết nữa. Truy vấn phụ của bạn sẽ dẫn đến một khóa chia sẻ (S) tồn tại trong thời gian ngắn trên bảng, khóa này sẽ được giải phóng ngay sau khi truy vấn phụ hoàn tất.

Tại thời điểm này, không có gì ngăn cản một giao dịch đồng thời chèn hàng mà bạn vừa xác minh không có mặt.

Tôi cần thực hiện sửa đổi nào để không có trường hợp ngoại lệ do vi phạm ràng buộc?

Thêm HOLDLOCK gợi ý cho truy vấn phụ của bạn sẽ hướng dẫn SQL Server giữ khóa cho đến khi giao dịch hoàn tất. (Trong trường hợp của bạn, đây là một giao dịch ngầm.) HOLDLOCK gợi ý tương đương với SERIALIZABLE gợi ý, bản thân nó tương đương với mức cách ly giao dịch có thể tuần tự hóa mà bạn tham khảo trong danh sách "các phương pháp tiếp cận khác".

HOLDLOCK gợi ý một mình sẽ đủ để giữ lại khóa S và ngăn một giao dịch đồng thời chèn hàng bạn đang bảo vệ. Tuy nhiên, bạn có thể sẽ thấy lỗi vi phạm khóa duy nhất của mình được thay thế bằng lỗi khóa, xảy ra với tần suất tương tự.

Nếu bạn chỉ giữ lại một khóa S trên bàn, hãy xem xét một cuộc chạy đua giữa hai nỗ lực đồng thời để chèn cùng một hàng, tiếp tục trong bước khóa - cả hai đều thành công trong việc có được khóa S trên bàn, nhưng cả hai đều không thể thành công trong việc giành được Exclusive (X) cần có khóa để thực hiện chèn.

May mắn thay, có một loại khóa khác cho trường hợp chính xác này, được gọi là khóa Cập nhật (U). Khóa U giống với khóa S với sự khác biệt sau:trong khi nhiều khóa S có thể được giữ đồng thời trên cùng một tài nguyên, mỗi lần chỉ có thể giữ một khóa U. (Nói một cách khác, trong khi các ổ khóa S tương thích với nhau (nghĩa là có thể cùng tồn tại mà không có xung đột), các khóa U không tương thích với nhau, nhưng có thể cùng tồn tại cùng với các ổ khóa S; và xa hơn nữa, các khóa dành riêng (X) thì không tương thích với khóa S hoặc U)

Bạn có thể nâng cấp khóa S ngầm trên truy vấn phụ của mình thành khóa U bằng cách sử dụng UPDLOCK gợi ý.

Hai lần thử đồng thời để chèn cùng một hàng trong bảng bây giờ sẽ được tuần tự hóa ở câu lệnh chọn ban đầu, vì điều này thu được (và giữ) một khóa U, không tương thích với một khóa U khác từ lần chèn đồng thời.

Giá trị NULL

Một vấn đề riêng biệt có thể phát sinh do FieldC cho phép các giá trị NULL.

Nếu ANSI_NULLS được bật (mặc định) thì kiểm tra bình đẳng FieldC=NULL sẽ trả về false, ngay cả trong trường hợp FieldC là NULL (bạn phải sử dụng IS NULL toán tử để kiểm tra null khi ANSI_NULLS đang bật). Vì FieldC là nullable, kiểm tra trùng lặp của bạn sẽ không hoạt động khi chèn giá trị NULL.

Để đối phó chính xác với null, bạn sẽ cần sửa đổi truy vấn phụ EXISTS của mình để sử dụng IS NULL toán tử thay vì = khi một giá trị NULL đang được chèn. (Hoặc bạn có thể thay đổi bảng để không cho phép NULL trong tất cả các cột có liên quan.)

Tài liệu tham khảo trực tuyến về sách SQL Server

  • Gợi ý về khóa
  • Khóa ma trận tương thích
  • 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. Bảo trì theo lịch trình của Cơ sở dữ liệu IS 24/7 trong MS SQL Server

  2. Cách trả về số nhóm tăng dần trên mỗi nhóm trong SQL

  3. Trả về danh sách các trình kích hoạt trong SQL Server

  4. cách khai báo biến toàn cục trong SQL Server ..?

  5. Chèn toàn bộ DataTable vào cơ sở dữ liệu cùng một lúc thay vì từng hàng?