Как отключить /reset уровень изоляции транзакций для SQL Server?

Возможно, я неправильно понимаю что-то о транзакциях или о том, что делает SQL Server, но рассмотрим следующий T-SQL:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
GO

BEGIN TRANSACTION

-- DO SOME READS AND OTHER THINGS

COMMIT

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

Возможно, это не имеет значения, но мне нравится теплое нечеткое ощущение, что я оставляю вещи так, как они были, когда я закончил делать то, что делаю. Возможно ли reset уровень изоляции вернуться в исходное состояние независимо от того, что было раньше?

Ответ 1

Если ваш код выполняется внутри хранимой процедуры, изменение применяется только в области хранимой процедуры - при восстановлении сохраненного proc уровень изоляции для соединения автоматически вернется к нему на предыдущем уровне:

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

(Игнорируя набор результатов из sys.objects, выдает значения 2, 4 и 2 в качестве уровней изоляции).

Ответ 2

Вы знаете текущий уровень от sys.dm_exec_sessions.transaction_isolation_level

Если вам нужно разбить партии, используйте SET CONTEXT_INFO, чтобы сохранить значение, которое позже можно будет прочитать из sys.dm_exec_sessions.

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)

Ответ 3

Решение GBNs для меня не работает. Я сомневаюсь, что он будет работать в другом месте.

Проблема заключается в том, что возврат к предыдущему уровню изоляции действителен только в контексте EXEC. Мой script приведен ниже. Обратите внимание, что он также не пытается изменить изоляцию, если текущая изоляция включает моментальные снимки. (Если вы попробуете, он потерпит неудачу).

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;