trzeba zrobić to w transakcji, aby zapewnić dwa jednoczesne klientów nie będzie wstawić samą fieldValue dwukrotnie:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
DECLARE @id AS INT
SELECT @id = tableId FROM table WHERE fi[email protected]
IF @id IS NULL
BEGIN
INSERT INTO table (fieldValue) VALUES (@newValue)
SELECT @id = SCOPE_IDENTITY()
END
SELECT @id
COMMIT TRANSACTION
można również użyć Double-checked locking celu zmniejszenia blokowania napowietrznych
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
Jak, dlaczego IZOLACJA POZIOM SERIALIZABLE jest konieczne, gdy jesteś wewnątrz serializable transakcji najpierw wybrać tha t trafienia tabeli tworzy blokadę zasięgu obejmującą miejsce, w którym powinien być rekord, więc nikt inny nie może wstawić tego samego rekordu, dopóki ta transakcja się nie skończy.
Bez ISOLATION LEVEL SERIALIZABLE, domyślny poziom izolacji (READ COMMITTED) nie blokowałby tabeli w czasie odczytu, więc pomiędzy SELECT i UPDATE ktoś mógłby nadal być w stanie wstawić. Transakcje z poziomem izolacji READ COMMITTED nie powodują blokady SELECT. Transakcje z REPEATABLE READS blokują rekord (jeśli został znaleziony), ale nie lukę.
Jakiego języka programowania używasz? To może być lepiej wykonane w ramach transakcji. –
możliwy duplikat [Tylko wstawianie wiersza, jeśli jeszcze go tam nie ma] (http://stackoverflow.com/questions/3407857/only-inserting-a-row-if-its-not-already-there) –
To jest starsze pytanie; Pytanie "Tylko wstawianie wiersza" powinno być zamknięte jako duplikat tego, a nie odwrotnie. –