Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

SE ESISTE, ALLORA SELEZIONA ELSE INSERT E POI SELEZIONA

Devi farlo durante la transazione per assicurarti che due client simultanei non inseriscano due volte lo stesso fieldValue:

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

puoi anche utilizzare Blocco a doppia verifica per ridurre il sovraccarico di bloccaggio

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

Per quanto riguarda il motivo per cui ISOLATION LEVEL SERIALIZABLE è necessario, quando ci si trova all'interno di una transazione serializzabile, il primo SELECT che colpisce la tabella crea un blocco di intervallo che copre il punto in cui dovrebbe essere il record, quindi nessun altro può inserire lo stesso record fino al termine di questa transazione.

Senza ISOLATION LEVEL SERIALIZABLE, il livello di isolamento predefinito (READ COMMITTED) non bloccherebbe la tabella al momento della lettura, quindi tra SELECT e UPDATE, qualcuno sarebbe ancora in grado di inserire. Le transazioni con livello di isolamento READ COMMITTED non causano il blocco di SELECT. Le transazioni con LETTURE RIPETIBILI bloccano il record (se trovato) ma non lo spazio vuoto.