Как SqlConnection управляет IsolationLevel? - PullRequest
20 голосов
/ 21 сентября 2010

В этой статье MSDN говорится, что:

Уровень изоляции имеет область действия всего соединения, и после установки для соединения с помощью инструкции SET TRANSACTION ISOLATION LEVEL он остается вдействует до тех пор, пока соединение не будет закрыто или не будет установлен другой уровень изоляции.Когда соединение закрывается и возвращается в пул, уровень изоляции из последнего оператора SET TRANSACTION ISOLATION LEVEL сохраняется.Последующие соединения, повторно использующие объединенное соединение, используют уровень изоляции, который действовал во время объединения соединения.

Класс SqlConnection не имеет члена, который может содержать уровень изоляции.Так как же соединение знает, на каком уровне изоляции работать?

Причина, по которой я спрашиваю об этом, заключается в следующем сценарии:

  1. Я открыл транзакцию с использованием TransactionScope в режиме Serializable, скажем «T1».
  2. Открыто соединение для T1.
  3. T1 завершено / удалено, соединение возвращается в пул соединений.
  4. Вызов другого запроса на том же соединении (после получения его из пула соединений), и этот запрос выполняется вСериализуемый режим !!!

Проблема:

  1. Как пул-соединение все еще знает, какой уровень изоляции был связан с ним ???
  2. Каквернуть его на какой-либо другой уровень транзакции ???

Разрешение:
Причина, по которой пульные соединения возвращают сериализуемый уровень изоляции, заключается в следующемпричина:

  1. У вас есть один пул соединений (скажем, CP1)
  2. CP1 может иметь 50 соединений.
  3. Вы выбираете одно соединение C1 из CP1 и выполняете его с помощьюСериализуемый.У этого соединения установлен уровень изоляции.Что бы вы ни делали, это не будет сброшено (если только это соединение не используется для выполнения кода с другим уровнем изоляции).
  4. После выполнения запроса C1 (Serializable) возвращается к CP1.
  5. Если шаги 1-4 выполняются снова, тогда используемое соединение может быть чем-то иным, чем C1, скажем, C2 или C3.Таким образом, этому уровню изоляции также будет присвоено значение Serializable.
  6. Итак, для Serialzable медленно устанавливается несколько соединений в CP1.
  7. Когда вы выполняете запрос, для которого не задана явная настройка уровня изоляции.После этого соединение, выбранное из CP1, определит уровень изоляции.Например, если такой запрос запрашивает соединение и CP1 использует C1 (Serializable) для выполнения этого запроса, тогда этот запрос будет выполняться в режиме Serializable, даже если вы явно не устанавливали его.

Надеюсь, чтоочищает несколько сомнений.:)

Ответы [ 4 ]

10 голосов
/ 21 сентября 2010

Уровни изоляции реализованы в базовой СУБД, скажем, SqlServer.Установка уровня изоляции наиболее вероятно устанавливает команды SQL, которые устанавливают уровень изоляции для соединения.

СУБД поддерживает уровень изоляции, пока соединение остается открытым.Поскольку соединения помещаются в пул, они остаются открытыми и сохраняют настройки, сделанные ранее.

При работе с уровнями изоляции следует либо сбросить уровень изоляции в конце любой транзакции, либо, что еще лучшеустановите его при запросе нового соединения.

6 голосов
/ 21 сентября 2010

SqlConnection.BeginTransaction принимает аргумент IsolationLevel, и именно так контролируется уровень изоляции соединений SqlClient. Другой вариант - использовать универсальный System.Transactions и указать уровень изоляции в TransactionOptions.IsolationLevel, передаваемом конструктору TransactionScope . Как в модели программирования SqlClient, так и в System.Transactions уровень изоляции должен быть явно указан для каждой транзакции. Если не указан, будет использоваться значение по умолчанию (Read Committed для SqlClient, Serializable for System.Transactions).

Соединения в пуле не используются вслепую. У них есть скрытые внутренние члены для отслеживания текущего состояния, такого как текущая транзакция, ожидающие результаты и т. Д., И инфраструктура может очистить соединение, возвращаемое в пул. То, что состояние не отображается в модели программирования, это не значит, что его там нет (это относится к любому классу библиотеки, любой конструктор класса может скрыть член под зонтиком internal).

И, наконец, любое соединение, повторно используемое из пула, которое он вызывает, sp_reset_connection, который является серверной процедурой, которая очищает состояние сеанса на стороне сервера.

4 голосов
/ 15 ноября 2011

Не возвращает уровень изоляции к исходному значению.В примере с использованием сущностей для сброса уровня требуется пустая транзакция (хотя она не требует фиксации (не требуется .Complete ()).

Попытка изменить уровень ISO с помощью SP в БДсервер не работает. Выходные данные:

До: ReadCommitted
Во время: Сериализуемый
После: Сериализуемый
После Сброса SP Попытка: Сериализуемый
Во время сброса XACT: ReadCommitted
После сброса XACT: ReadCommitted

// using Dbg = System.Diagnostics.Debug;
XactIso.iso isoEntity = new XactIso.iso();
using (isoEntity)
{
    Dbg.WriteLine("Before: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault());

    var xactOpts = new TransactionOptions();
    xactOpts.IsolationLevel = System.Transactions.IsolationLevel.Serializable;

    using (TransactionScope xact = new TransactionScope(TransactionScopeOption.Required, xactOpts))
    {
        Dbg.WriteLine("During: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault());
        xact.Complete();
    }

    Dbg.WriteLine("After: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault());

    isoEntity.usp_SetXactIsoLevel("ReadCommitted");

    Dbg.WriteLine("After Reset by SP Attempt: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault());
    // failed

    var xactOpts2 = new TransactionOptions();
    xactOpts2.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
    using (TransactionScope xact2 = new TransactionScope(TransactionScopeOption.Required, xactOpts2))
        Dbg.WriteLine("During Reset by XACT: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault());
    // works w/o commit

    Dbg.WriteLine("After Reset by XACT: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault());
}

, где по ссылке

proc [Common].[usp_GetXactIsoLevel]
as
begin          
    select         
        case transaction_isolation_level 
            WHEN 0 THEN 'Unspecified' 
            WHEN 1 THEN 'ReadUncommitted' 
            WHEN 2 THEN 'ReadCommitted' 
            WHEN 3 THEN 'RepeatableRead' 
            WHEN 4 THEN 'Serializable' 
            WHEN 5 THEN 'Snapshot' 
        end as lvl
     from sys.dm_exec_sessions 
    where session_id = @@SPID;
end

и (не работает):

proc [Common].[usp_SetXactIsoLevel]
    @pNewLevel    varchar(30)
as
begin

    if @pNewLevel = 'ReadUncommitted'
        SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    else if @pNewLevel = 'ReadCommitted'
        SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
    else if @pNewLevel = 'RepeatableRead'
        SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
    else if @pNewLevel = 'Serializable'
        SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    else if @pNewLevel = 'Snapshot'
        SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
    else
        raiserror('Unrecognized Transaction Isolation Level', 16, 1);         
end        
1 голос
/ 04 сентября 2014

В SQL Server 2014 уровень изоляции для соединения в пуле сбрасывается при возврате соединения в пул. Смотрите это сообщение на форуме

"в SQL 2014, для драйверов клиентов с версией 7.3 TDS или выше, сервер SQL будет сбрасывать уровень изоляции транзакции по умолчанию (чтение зафиксировано) для соединений в пуле. Для клиентов с версией TDS ниже 7.3 они будут иметь старое поведение при работает против SQL 2014. "

Обновление 2017-04-22

К сожалению, это позже было «нефиксировано» в SQL Server 2014 CU6 и SQL Server 2014 с пакетом обновления 1 (SP1) CU1, поскольку в нем появилась ошибка:

ИСПРАВЛЕНИЕ: Уровень изоляции транзакции сбрасывается неправильно, когда соединение SQL Server выпущено в SQL Server 2014

"Предположим, что вы используете класс TransactionScope в клиентском исходном коде SQL Server и не открываете явно соединение SQL Server в транзакции. Когда соединение SQL Server освобождается, уровень изоляции транзакции сбрасывается неправильно. «

...