Musíte to udělat v transakci, abyste zajistili, že dva simultánní klienti nevloží stejnou hodnotu pole dvakrát:
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
můžete také použít Double-checked zamykání snížit režii zamykání
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
Pokud jde o to, proč je nezbytná SERIALIZAČNÍ ÚROVEŇ IZOLACE, když jste uvnitř serializovatelné transakce, první SELECT, který zasáhne tabulku, vytvoří zámek rozsahu pokrývající místo, kde by měl být záznam, takže nikdo jiný nemůže vložit stejný záznam, dokud tato transakce neskončí.
Bez IZOLACE LEVEL SERIALIZABLE by výchozí úroveň izolace (READ COMMITTED) neuzamkla tabulku v době čtení, takže mezi SELECT a UPDATE by někdo stále mohl vkládat. Transakce s úrovní izolace READ COMMITTED nezpůsobí uzamčení SELECT. Transakce s REPEATABLE READS uzamknou záznam (pokud byl nalezen), ale ne mezeru.