SQL Server: vazamentos de nível de isolamento nas conexões agrupadas

Como demonstrado pelas perguntas anteriores do Stack Overflow TransactionScope e pool de conexão eComo o SqlConnection gerencia IsolationLevel?), o nível de isolamento da transação vaza nas conexões agrupadas com o SQL Server e o ADO.NET (também System.Transactions e EF, porque eles são criados com base no ADO.NET

Isso significa que a seguinte sequência perigosa de eventos pode ocorrer em qualquer aplicativo:

contece uma solicitação que requer uma transação explícita para garantir a consistência dos dado Qualquer outra solicitação é recebida e não usa uma transação explícita porque está apenas fazendo leituras acríticas. Essa solicitação agora será executada como serializável, potencialmente causando bloqueios e impasses perigosos

A questão: Qual é a melhor maneira de evitar esse cenário? É realmente necessário usar transações explícitas em todos os lugares agor

Aqui está uma reprodução independente. Você verá que a terceira consulta herdou o nível Serializable da segunda consulta.

class Program
{
    static void Main(string[] args)
    {
        RunTest(null);
        RunTest(IsolationLevel.Serializable);
        RunTest(null);
        Console.ReadKey();
    }

    static void RunTest(IsolationLevel? isolationLevel)
    {
        using (var tran = isolationLevel == null ? null : new TransactionScope(0, new TransactionOptions() { IsolationLevel = isolationLevel.Value }))
        using (var conn = new SqlConnection("Data Source=(local); Integrated Security=true; Initial Catalog=master;"))
        {
            conn.Open();

            var cmd = new SqlCommand(@"
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, @@SPID
     from sys.dm_exec_sessions 
    where session_id = @@SPID", conn);

            using (var reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                {
                    Console.WriteLine("Isolation Level = " + reader.GetValue(0) + ", SPID = " + reader.GetValue(1));
                }
            }

            if (tran != null) tran.Complete();
        }
    }
}

Resultado

Isolation Level = ReadCommitted, SPID = 51
Isolation Level = Serializable, SPID = 51
Isolation Level = Serializable, SPID = 51 //leaked!

questionAnswers(6)

yourAnswerToTheQuestion