【问题标题】:Detecting rollback in SQL Server在 SQL Server 中检测回滚
【发布时间】:2019-10-12 15:41:44
【问题描述】:

在涉及两个或多个语句时尝试检测回滚条件。对于SqlCommand.ExecuteNonQuery 方法,docs 表示

如果没有检测到有助于计数的语句,则返回 值为-1。如果发生回滚,返回值也是-1。

我故意将-1 作为引用完整性约束的引用表中的无效条目插入。

string sql = $@"
    BEGIN TRANSACTION
        BEGIN TRY
            DELETE FROM CustomerContact WHERE CustomerId = @Id
            INSERT INTO CustomerContact(CustomerId, ContactId) VALUES (3, -1)
            COMMIT TRANSACTION
        END TRY
        BEGIN CATCH
            ROLLBACK TRANSACTION
        END CATCH";

using (SqlCommand command = new SqlCommand(sql, connection))
{
    command.Connection.Open();
    command.Parameters.Add("Id", SqlDbType.Int).Value = id;
    int result = command.ExecuteNonQuery();
    Console.WriteLine(result); // -> returns affected deleted rows but not -1
}

回滚按预期工作,但我没有从ExecuteNonQuery 获得-1,而是从DELETE 操作中获得了一些受影响的行(第一条语句

我之前确实使用过SqlTransaction,但我正在测试基于嵌入式 SQL 的事务的行为。

【问题讨论】:

  • 创建一个包含两个语句的事务和锁,检查事务的回滚?
  • 对不起,你能帮忙提供一个代码吗?
  • 对于初学者,不要使用 ExecuteNonQuery()。它只有一个非常有限的返回值。 ExecuteScalar 是从 StoredProcedure 获得任何有用返回值的最小值。归根结底,函数返回值就是您所追求的。或者检查任何记录“此操作已回滚”的结果属性。
  • 我建议您只需将CATCH 块放入以指示错误并发生回滚IF @@TRANCOUNT > 0 ROLLBACK; THROW;。另外,添加SET XACT_ABORT ON; 以确保事务在超时时立即回滚。
  • @DanGuzman 你能写一个答案吗,非常感谢。我是新手。

标签: c# sql-server transactions ado.net


【解决方案1】:

我建议您只输入CATCH 块以指示错误并发生相应的回滚,而不是尝试检测ROLLBACK 本身。

最好在 T-SQL 事务中指定SET XACT_ABORT ON;,以确保在超时的情况下立即回滚事务。这是因为超时发生在客户端,API 取消正在运行的查询并阻止带有 ROLLBACK 的 CATCH 块执行。然后,连接会随着打开的事务返回到池中,并且锁尚未释放。虽然当池连接被重用/重置或关闭时事务最终会被回滚,但 XACT_ABORT 设置将导致立即发生并释放资源锁。

以下是我在大多数情况下推荐的 T-SQL 事务管理和结构化错误处理模式。另外,请注意在avoid surprises 中大量使用分号。

string sql = $@"
        SET XACT_ABORT ON;
        BEGIN TRY
            BEGIN TRANSACTION;
            DELETE FROM CustomerContact WHERE CustomerId = @Id;
            INSERT INTO CustomerContact(CustomerId, ContactId) VALUES (3, -1);
            COMMIT TRANSACTION;
        END TRY
        BEGIN CATCH
            IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
            THROW;
        END CATCH";

try
{
    using (SqlCommand command = new SqlCommand(sql, connection))
    {
        command.Connection.Open();
        command.Parameters.Add("Id", SqlDbType.Int).Value = id;
        int result = command.ExecuteNonQuery();
        Console.WriteLine(result); // -> returns affected deleted rows but not -1
    }
}
catch
{
    Console.WriteLine('handle exception here');
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-24
    • 1970-01-01
    • 2011-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    相关资源
    最近更新 更多