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.