【发布时间】:2014-04-21 09:19:44
【问题描述】:
考虑以下表格方案:
T2 --> T1 <-- T3
T2 指的是 T1,T3 指的是 T1,因此我无法从 T1 中删除在 T2 或 T3 中引用的行。
现在,使用以下代码:
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 版本上执行会产生相同的结果。表 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 进行比较,它们与信。)
这是分析器的输出:
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 如何确保代码在事务中执行?
【问题讨论】:
标签: c# transactions transactionscope