正如先前的堆栈溢出问题(TransactionScope和连接池以及SqlConnection如何管理IsolationLevel?)所证明的那样,事务隔离级别在与SQL Server和ADO.NET(以及System.Transactions和EF的池连接)之间泄漏,因为它们建立在ADO.NET)。
这意味着在任何应用程序中都可能发生以下危险的事件序列:
请求发生,需要显式事务以确保数据一致性
其他任何不使用显式事务的请求都会出现,因为它仅在执行非关键读取。现在,该请求将以可序列化的方式执行,从而可能导致危险的阻塞和死锁
问题:预防这种情况的最佳方法是什么?现在真的需要在任何地方使用显式事务吗?
这是一个自包含的副本。您将看到第三个查询将继承第二个查询的可序列化级别。
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();
}
}
}
输出:
Isolation Level = ReadCommitted, SPID = 51
Isolation Level = Serializable, SPID = 51
Isolation Level = Serializable, SPID = 51 //leaked!
慕虎7371278
相关分类