Du skal gøre dette i transaktionen for at sikre, at to samtidige klienter ikke indsætter samme fieldValue to gange:
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
du kan også bruge Dobbeltkontrolleret låsning for at reducere overhead ved låsning
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
Med hensyn til hvorfor ISOLATION LEVEL SERIALIZABLE er nødvendigt, når du er inde i en serialiserbar transaktion, skaber den første SELECT, der rammer bordet, en intervallås, der dækker det sted, hvor posten skal være, så ingen andre kan indsætte den samme post, før denne transaktion slutter.
Uden ISOLATIONSNIVEAU SERIALIZABLE, ville standardisolationsniveauet (READ COMMITTED) ikke låse tabellen på læsetidspunktet, så mellem SELECT og UPDATE ville nogen stadig være i stand til at indsætte. Transaktioner med READ COMMITTED isolationsniveau får ikke SELECT til at låse. Transaktioner med GENTAGBARE LÆSNINGER låser posten (hvis den findes), men ikke hullet.