猿问

SQL Server:池连接之间的隔离级别泄漏

正如先前的堆栈溢出问题(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!


大话西游666
浏览 576回答 3
3回答

慕虎7371278

在SQL Server 2014中,此问题似乎已得到解决。如果使用TDS协议7.3或更高版本。在SQL Server 12.0.2000.8版上运行,输出为:ReadCommittedSerializableReadCommitted不幸的是,此更改未在任何文档中提及,例如: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连接后,将不正确地重置事务隔离级别。”
随时随地看视频慕课网APP
我要回答