2011-01-07 10 views
10

tal vez estoy mal algo acerca de las transacciones o lo que SQL Server está haciendo, pero considere lo siguiente T-SQL:¿Cómo desactivo/restablezco un nivel de aislamiento de transacción para 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? 

Tal vez no importa, pero me gusta la sensación borrosa caliente que me voy cosas como eran una vez que he terminado de hacer lo que estoy haciendo. ¿Es posible restablecer el nivel de aislamiento al estado original independientemente de lo que era el estado anterior?

Respuesta

12

Si el código se ejecuta dentro de un procedimiento almacenado, el cambio sólo se aplica en el ámbito del procedimiento almacenado - cuando las almacenado devuelve proc, el nivel de aislamiento para la conexión pasa automáticamente a su nivel anterior:

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 el conjunto de resultados de sys.objects, esto produce 2, 4 y 2 como niveles de aislamiento).

+0

Mi código terminó en un proceso almacenado, así que es bueno saberlo. ¡Gracias! – DJTripleThreat

+0

@Damien_The_Unbeliever ¿Esto se aplica también a los desencadenantes? –

+0

@SpongebobComrade - yes - ['SET TRANSACTION ISOLATION LEVEL'] (https://msdn.microsoft.com/en-GB/library/ms173763.aspx):" Si ejecuta SET TRANSACTION ISOLATION LEVEL en un procedimiento almacenado o disparador , cuando el objeto devuelve el control, el nivel de aislamiento se restablece al nivel vigente cuando se invoca el objeto " –

14

saber el nivel actual de sys.dm_exec_sessions.transaction_isolation_level

Si necesita abarcar lotes, a continuación, utilizar SET CONTEXT_INFO para preservar el valor que también se pueden leer desde sys.dm_exec_sessions más adelante.

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. Eso es realmente útil! Gracias por publicar eso. – DJTripleThreat

1

La solución GBNs no funciona para mí. Dudo que funcione en otro lado.

El problema es que el retorno al nivel de aislamiento anterior solo es válido en el contexto del EXEC. Mi guion esta abajo Tenga en cuenta que tampoco intenta cambiar el aislamiento si el aislamiento actual incluye instantáneas. (Fallará si lo intenta).

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; 
Cuestiones relacionadas