LINQ + TransactionScope在SQL Server Profiler中不会改变隔离级别

4

我正在使用以下格式通过linq提交对我的数据库所做的更改。

Begin Transaction (Scope Serialized, Required)
    Check Business Rule 1...N
    MyDataContext.SubmitChanges()
    Save Changes Done In Previous Query To Log File
End Transaction Scope

但是在 SQL Server 分析器中,我看到连接开始时出现了以下行。
set transaction isolation level read committed

我阅读了这篇文章(http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/93a45026-0425-4d49-a4ac-1b882e90e6d5),并认为我已经得到了答案;
直到我看到了这个(https://connect.microsoft.com/VisualStudio/feedback/details/565441/transactionscope-linq-to-sql?wa=wsignin1.0)在Microsoft Connect上的内容。
请问有人能告诉我我的代码是否实际上是在序列化隔离级别下执行,还是只是在读取提交时运行?

我倾向于相信您在 Profiler 中看到的内容... - Mitch Wheat
但是在其中一篇帖子中也提到,分析器只显示连接开始时的隔离级别。:S - Dasith Wijes
如果您在分析器中没有看到与隔离级别相关的其他语句,则那就是隔离级别。 - Mitch Wheat
1
我应该寻找哪些语句?我发现了一些非常有趣的东西,就是在上面的查询之后立即出现了Audit:Login语句,设置了事务隔离级别为Serializable,但是此时我想要在序列化隔离中执行的查询已经被执行了。 - Dasith Wijes
1
@Mitch,稍微微妙一些,我也无法确定“TM:Begin Tran”中tran的隔离级别,但我可能漏掉了一个列。 - Sam Saffron
1
@Mitch,虽然我经常使用Profiler来查看数据库层面上的实际情况,但在这种情况下,Profiler中的Audit Login语句将显示设置隔离级别之前的隔离级别。在Profiler中查看隔离级别的设置是困难的(正如http://entityframework.codeplex.com/workitem/1712中_divega_的评论所解释的那样)。要确定,请查看sys.dm_exec_session视图中的会话记录。Sam提到了一种方法。您会发现,Profiler报告的`Audit Login`通常与当前隔离级别不匹配。 - DeveloperRob
3个回答

7

这取决于您如何创建事务。

如果您使用内联SQL开始它(例如BEGIN TRAN),L2S将不会意识到该事务,并将在READ COMMITTED中启动一个新的嵌套事务。

但是,如果您使用System.Transaction或在DataContext上设置了事务,则SubmitChanges将参与该事务。

如果您选择TM: Begin TranTM: Commit Tran事件类别,可以在Profiler中看到这些事务的启动和停止。

注意:ADO.Net不会发出BEGIN TRAN,也不会在批处理中发出SET TRANSACTION ISOLATION,这是在较低级别完成的。

如果您真的想确认行为,请在一个表上创建触发器,将当前隔离级别插入日志表中并进行检查。

您可以通过运行以下命令来获取当前隔离级别:

SELECT CASE transaction_isolation_level 
WHEN 0 THEN 'Unspecified' 
WHEN 1 THEN 'Read Uncommitted' 
WHEN 2 THEN 'Read Committed' 
WHEN 3 THEN 'Repeatable Read' 
WHEN 4 THEN 'Serializable' 
WHEN 5 THEN 'Snapshot' END AS TRANSACTION_ISOLATION_LEVEL 
FROM sys.dm_exec_sessions 
where session_id = @@SPID

我像我的帖子中所示一样通过 "Begin Transaction(Scope Serialized,Required)" 开始了我的事务。不知道为什么服务器分析器中没有显示隔离级别?请参阅我发布的链接。 - Dasith Wijes

1

来自http://entityframework.codeplex.com/workitem/1712

TransactionScope使用远程API调用而不是SQL命令在SQL Server中执行事务。这些API调用未包含在SQL Profiler的标准跟踪中。

您可以通过转到“事件选择”页面,单击“显示所有事件”复选框,然后选择“事务”类别中的所有事件来包括它们。这将允许您查看诸如“TM:Begin Tran Starting”、“SQLTransaction”和“TM:Begin Tran Completed”等事件实际发生的时间。

您还可以在“事件选择”页面的TSQL事件中检查TransactionID列,以查看正在执行的每个SQL批处理与哪个事务相关联。

不幸的是,我不知道在SQL Profiler中观察每个命令正在执行的有效隔离级别的直接方法。但有一种间接的方法...

当连接打开时,您将在跟踪中看到一个“审核登录”事件。在许多情况下,此事件将包含隔离级别。现在,“审核登录”发生在实际隔离级别设置之前,因此报告的隔离级别将不准确反映即将开始的事务的隔离级别。以下是一些有关如何解释它的提示: 当连接打开实际上命中新连接时,它将始终报告默认事务隔离级别,例如,您将看到“set transaction isolation level read uncommitted”(正如我所说,这与事务的有效隔离级别无关,因为该事务将在稍后设置) 在打开连接并返回到连接池(即关闭)后,随后的连接打开将实际上重用来自池的现有连接。在这种情况下,“审核登录”将报告上次将连接返回到池时设置的隔离级别。这可以帮助您查看在事后使用的隔离级别。 例如,在您的代码片段中,连接最后一次打开以回滚事务(因为您没有明确标记事务已完成)。在那个“审核登录”事件中,您应该能够看到在先前使用连接执行查询时有效的隔离级别,表示为“set transaction isolation level read uncommitted”行。

1
我的猜测是你创建了DataContext,然后使用了TransactionScope。你必须在TransactionScope内部打开连接才能将其列入事务。

不是的。那里有一个属性,可以指示上下文使用任何现有事务(或需要新事务)。这是完全不同的问题。 - Dasith Wijes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接