TransactionScope和回滚

时间:2014-04-21 09:19:45

标签: c# transactions transactionscope

考虑以下表格方案:

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 TRANSET 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如何确保代码在事务中执行吗?

1 个答案:

答案 0 :(得分:1)

尝试将您的查询更改为:

SELECT @@OPTIONS USE [TransactionScopeTests]; DELETE FROM T3; DELETE FROM T1;

您应该在会话级别看到不同的选项,因为这是事务范围的变化。试一试,选项应该不同!