U moet dit in transactie doen om ervoor te zorgen dat twee gelijktijdige clients niet twee keer dezelfde fieldValue invoegen:
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
u kunt ook Double-checked_locking">Double-checked_locking gebruiken om vergrendeling overhead te verminderen
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
Wat betreft waarom ISOLATIENIVEAU SERIALISEERBAAR nodig is, wanneer u zich in een serialiseerbare transactie bevindt, creëert de eerste SELECT die de tafel raakt een bereikvergrendeling die de plaats bedekt waar het record zou moeten zijn, zodat niemand anders hetzelfde record kan invoegen totdat deze transactie eindigt.
Zonder ISOLATIENIVEAU SERIALIZABLE zou het standaard isolatieniveau (LEZEN COMMITTED) de tabel niet vergrendelen tijdens het lezen, dus tussen SELECT en UPDATE zou iemand nog steeds kunnen invoegen. Transacties met het isolatieniveau READ COMMITTED zorgen er niet voor dat SELECT wordt vergrendeld. Transacties met HERHAALBARE LEZEN vergrendelen het record (indien gevonden), maar niet het gat.