考虑以下表格方案:
T2 --> T1 <-- T3
T2指的是T1,T3指的是T1,因此我无法删除T2或T3中引用的T1行。
现在,使用以下代码:
using (var sqlConnection = new SqlConnection(ConnectionString))
{
sqlConnection.Open();
using (SqlCommand sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = "USE [TransactionScopeTests]; DELETE FROM T3; DELETE FROM T1;"; // DELETE FROM T1 will cause violation of integrity, because rows from T2 are still using rows from T1.
sqlCommand.ExecuteNonQuery();
}
}
此代码在SQL Server 2014 LocalDb或Sql Server 2012 Developer Edition上执行,产生相同的结果。表T3
为空,但表T1
保持不变。
将探查器连接到此查询会导致执行以下SQL:
Audit Login
:
-- network protocol: Named Pipes
set quoted_identifier on
set arithabort off
set numeric_roundabort off
set ansi_warnings on
set ansi_padding on
set ansi_nulls on
set concat_null_yields_null on
set cursor_close_on_commit off
set implicit_transactions off
set language us_english
set dateformat mdy
set datefirst 7
set transaction isolation level read committed
然后SQL:BatchStarting
USE [TransactionScopeTests]; DELETE FROM T3; DELETE FROM T1;
然后是Audit Logout
,然后是RPC:Completed
exec sp_reset_connection
查看表格,T3
为空,T1
不是。
但是,如果我们将代码包装在TransactionScope中:
using (var transactionScope = new TransactionScope())
{
using (var sqlConnection = new SqlConnection(ConnectionString))
{
sqlConnection.Open();
using (SqlCommand sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = "USE [TransactionScopeTests]; DELETE FROM T3; DELETE FROM T1;";
sqlCommand.ExecuteNonQuery();
}
transactionScope.Complete();
}
}
这将导致正确的行为。关闭连接后,将回滚事务。
然而,困扰我的是在分析正在发送的SQL时我看不到这种行为。我期待用BEGIN TRAN
或SET XACT_ABORT ON
或类似的东西打开连接,但我看不出差异(我确实将输出保存到文本文件并将它们与difftool进行比较,他们&# 39;与信相同。)
这是探查器的输出:
Audit Login
:
-- network protocol: Named Pipes
set quoted_identifier on
set arithabort off
set numeric_roundabort off
set ansi_warnings on
set ansi_padding on
set ansi_nulls on
set concat_null_yields_null on
set cursor_close_on_commit off
set implicit_transactions off
set language us_english
set dateformat mdy
set datefirst 7
set transaction isolation level read committed
然后SQL:BatchStarting
USE [TransactionScopeTests]; DELETE FROM T3; DELETE FROM T1;
然后审核Logout
,然后是RPC:Completed
exec sp_reset_connection
但是,在这种情况下,T3
会恢复原状,因为整个语句都失败了。
有人可以详细说明.NET如何确保代码在事务中执行吗?
答案 0 :(得分:1)
尝试将您的查询更改为:
SELECT @@OPTIONS
USE [TransactionScopeTests]; DELETE FROM T3; DELETE FROM T1;
您应该在会话级别看到不同的选项,因为这是事务范围的变化。试一试,选项应该不同!