Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

WENN VORHANDEN, DANN SONST AUSWÄHLEN, EINFÜGEN UND DANN AUSWÄHLEN

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.