正如先前的堆栈溢出问题(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 = 51Isolation Level = Serializable, SPID = 51Isolation Level = Serializable, SPID = 51 //leaked!
3 回答
慕虎7371278
TA贡献1802条经验 获得超4个赞
在SQL Server 2014中,此问题似乎已得到解决。如果使用TDS协议7.3或更高版本。
在SQL Server 12.0.2000.8版上运行,输出为:
ReadCommitted
Serializable
ReadCommitted
不幸的是,此更改未在任何文档中提及,例如:
SQL Server 2014中数据库引擎功能的行为更改
SQL Server 2014中数据库引擎功能的重大更改
但是更改已记录在Microsoft论坛上。
不幸的是,此问题后来在SQL Server 2014 CU6和SQL Server 2014 SP1 CU1中“未修复”,因为它引入了一个错误:
FIX:在SQL Server 2014中发布SQL Server连接时,错误地重置了事务隔离级别
“假定您在SQL Server客户端源代码中使用TransactionScope类,并且没有在事务中显式打开SQL Server连接。释放SQL Server连接后,将不正确地重置事务隔离级别。”
添加回答
举报
0/150
提交
取消