Sie müssen dies in der Transaktion tun, um sicherzustellen, dass zwei Clients gleichzeitig denselben fieldValue nicht zweimal einfügen:
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
Sie können auch Double-checked locking verwenden um den Locking-Overhead zu reduzieren
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
Warum ISOLATION LEVEL SERIALIZABLE erforderlich ist, wenn Sie sich in einer serialisierbaren Transaktion befinden, erstellt das erste SELECT, das die Tabelle trifft, eine Bereichssperre, die die Stelle abdeckt, an der sich der Datensatz befinden sollte, sodass niemand sonst denselben Datensatz einfügen kann, bis diese Transaktion endet.
Ohne ISOLATION LEVEL SERIALIZABLE würde die Standard-Isolationsstufe (READ COMMITTED) die Tabelle zur Lesezeit nicht sperren, sodass zwischen SELECT und UPDATE immer noch jemand etwas einfügen könnte. Transaktionen mit der Isolationsstufe READ COMMITTED führen nicht zum Sperren von SELECT. Transaktionen mit REPEATABLE READS sperren den Datensatz (falls gefunden), aber nicht die Lücke.