Bạn cần thực hiện điều này trong giao dịch để đảm bảo hai ứng dụng khách đồng thời sẽ không chèn cùng một fieldValue hai lần:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
DECLARE @id AS INT
SELECT @id = tableId FROM table WHERE [email protected]
IF @id IS NULL
BEGIN
INSERT INTO table (fieldValue) VALUES (@newValue)
SELECT @id = SCOPE_IDENTITY()
END
SELECT @id
COMMIT TRANSACTION
bạn cũng có thể sử dụng Khóa được kiểm tra kỹ để giảm chi phí khóa
DECLARE @id AS INT
SELECT @id = tableID FROM table (NOLOCK) WHERE [email protected]
IF @id IS NULL
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
SELECT @id = tableID FROM table WHERE [email protected]
IF @id IS NULL
BEGIN
INSERT INTO table (fieldValue) VALUES (@newValue)
SELECT @id = SCOPE_IDENTITY()
END
COMMIT TRANSACTION
END
SELECT @id
Đối với lý do tại sao SERIALIZABLE MỨC ISOLATION là cần thiết, khi bạn đang ở bên trong một giao dịch có thể tuần tự hóa, lệnh CHỌN đầu tiên chạm vào bảng sẽ tạo ra một khóa phạm vi bao phủ nơi cần có bản ghi, vì vậy không ai khác có thể chèn cùng một bản ghi cho đến khi giao dịch này kết thúc.
Nếu không có CẤP ĐỘ ISOLATION SERIALIZABLE, mức cô lập mặc định (READ COMMITTED) sẽ không khóa bảng tại thời điểm đọc, vì vậy giữa CHỌN và CẬP NHẬT, ai đó vẫn có thể chèn. Các giao dịch có mức cách ly READ COMMITTED không khiến CHỌN bị khóa. Các giao dịch với ĐỌC LẶP LẠI sẽ khóa bản ghi (nếu được tìm thấy) nhưng không khóa khoảng trống.