2011-01-07 10 views
10

forse sto fraintendono qualcosa su transazioni o ciò che SQL Server sta facendo ma si consideri il seguente T-SQL:Come disinserire/ripristinare un livello di isolamento della transazione per SQL Server?

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 
GO 

BEGIN TRANSACTION 

-- DO SOME READS AND OTHER THINGS 

COMMIT 

-- OK, WHAT HAPPENS TO THE ISOLATION LEVEL AFTER THIS? 

Forse non importa, ma mi piace la sensazione inebriante che me ne vado le cose come erano quando ho finito di fare quello che sto facendo. È possibile ripristinare il livello di isolamento allo stato originale a prescindere dallo stato precedente?

risposta

12

Se il codice viene eseguito all'interno di una stored procedure, la modifica viene applicata solo durante il campo di applicazione della stored procedure - quando i rendimenti stored procedure, il livello di isolamento per la connessione torna automaticamente al suo livello precedente:

create procedure dbo.IsoTest 
as 
    set transaction isolation level serializable 
    begin transaction 

    select transaction_isolation_level FROM sys.dm_exec_sessions where session_id = @@SPID 

    select object_id from sys.objects 

    commit 
go 
select transaction_isolation_level FROM sys.dm_exec_sessions where session_id = @@SPID 
exec dbo.IsoTest 
select transaction_isolation_level FROM sys.dm_exec_sessions where session_id = @@SPID 

(Ignorando il set di risultati da sys.objects, queste uscite 2, 4 e 2 come livelli di isolamento).

+0

Il mio codice è finito in un processo memorizzato, quindi è bene sapere. Grazie! – DJTripleThreat

+0

@Damien_The_Unbeliever Questo vale anche per i trigger? –

+0

@SpongebobComrade - yes - ['SET TRANSACTION ISOLATION LEVEL'] (https://msdn.microsoft.com/en-GB/library/ms173763.aspx):" Se si emette SET TRANSACTION ISOLATION LEVEL in una stored procedure o trigger , quando l'oggetto restituisce il controllo, il livello di isolamento viene ripristinato al livello in vigore quando l'oggetto è stato richiamato " –

14

Voi conoscete il livello di corrente da sys.dm_exec_sessions.transaction_isolation_level

Se avete bisogno di estendersi lotti, quindi utilizzare SET CONTEXT_INFO di preservare il valore che può anche essere letto da sys.dm_exec_sessions in seguito.

DECLARE @CurrentIsolationLevel smallint 

SELECT @CurrentIsolationLevel = transaction_isolation_level 
FROM sys.dm_exec_sessions 
WHERE session_id = @@SPID 

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 
BEGIN TRANSACTION 
-- DO SOME READS AND OTHER THINGS 
COMMIT 

DECLARE @SQL varchar(200) 
SELECT @SQL = 'SET TRANSACTION ISOLATION LEVEL ' + 
     CASE @CurrentIsolationLevel 
      WHEN 1 THEN 'READ UNCOMMITTED' 
      WHEN 2 THEN 'READ COMMITTED' 
      WHEN 3 THEN 'REPEATABLE READ' 
      WHEN 4 THEN 'SERIALIZABLE' 
      WHEN 5 THEN 'SNAPSHOT' 
     END 
EXEC (@sql) 
+0

+1. Questo è veramente utile! Grazie per aver postato questo. – DJTripleThreat

1

La soluzione GBN non funziona per me. Dubito che funzionerà altrove.

Il problema è che il ritorno al precedente livello di isolamento è valido solo nel contesto dell'EXEC. La mia sceneggiatura è sotto Si noti che non tenta di modificare l'isolamento se l'isolamento corrente include istantanee. (Fallirà se proverai).

DECLARE @initalIsoloationLevel nvarchar(25) 

SELECT @initalIsoloationLevel = 
     CASE 
      WHEN transaction_isolation_level = 1 
      THEN 'READ UNCOMMITTED' 
      WHEN transaction_isolation_level = 2 
       AND is_read_committed_snapshot_on = 1 
      THEN 'READ COMMITTED SNAPSHOT' 
      WHEN transaction_isolation_level = 2 
       AND is_read_committed_snapshot_on = 0 
      THEN 'READ COMMITTED' 
      WHEN transaction_isolation_level = 3 
      THEN 'REPEATABLE READ' 
      WHEN transaction_isolation_level = 4 
      THEN 'SERIALIZABLE' 
      WHEN transaction_isolation_level = 5 
      THEN 'SNAPSHOT' 
      ELSE NULL 
     END 
FROM sys.dm_exec_sessions AS s 
WHERE session_id = @@SPID 

    /* Changing isolation level is not supported with snapshots */ 
IF @initalIsoloationLevel NOT LIKE '%SNAP%' AND @initalIsoloationLevel is NOT NULL 
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 


/****** DO YOUR STUFF HERE ******/ 


    /* Changing isolation level is not supported with snapshots */ 
IF @initalIsoloationLevel = 'READ COMMITTED' 
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED; 
ELSE IF @initalIsoloationLevel = 'REPEATABLE READ' 
    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; 
ELSE IF @initalIsoloationLevel = 'SERIALIZABLE' 
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 
Problemi correlati