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 perigososA 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!