简体   繁体   English

在 SQL 服务器中检测回滚

[英]Detecting rollback in SQL Server

Trying to detect a rollback condition when there are two or more statements involved.当涉及两个或多个语句时尝试检测回滚条件。 For SqlCommand.ExecuteNonQuery Method, The docs says对于SqlCommand.ExecuteNonQuery方法, 文档

If no statements are detected that contribute to the count, the return value is -1.如果未检测到有助于计数的语句,则返回值为 -1。 If a rollback occurs, the return value is also -1.如果发生回滚,则返回值也是 -1。

I'm inserting -1 on purpose as an invalid entry in the referenced table having referential integrity constraints.我故意插入-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
}

Rollback is working as expected but I'm not getting the -1 from ExecuteNonQuery , instead, I get a number of affected rows from the DELETE operation ( the first statement )回滚按预期工作,但我没有从ExecuteNonQuery获得-1 ,相反,我从DELETE操作(第一条语句)中获得了许多受影响的行

I did use SqlTransaction earlier but I'm testing out the behavior of embedded SQL based transactions.我之前确实使用过SqlTransaction ,但我正在测试基于嵌入式 SQL 的事务的行为。

I suggest you just throw in the CATCH block to indicate an error and corresponding rollback occurred rather than try to detect the ROLLBACK itself.我建议您只输入CATCH块以指示错误并发生相应的回滚,而不是尝试检测ROLLBACK本身。

It's a good practice to specify SET XACT_ABORT ON;最好指定SET XACT_ABORT ON; with T-SQL transactions to ensure the transaction is rolled back immediately in the case of a timeout.使用 T-SQL 事务确保事务在超时的情况下立即回滚。 This is because timeouts occur on the client side, where the API cancels the running query and prevents the CATCH block with the ROLLBACK from executing.这是因为超时发生在客户端,其中 API 取消正在运行的查询并阻止带有ROLLBACK的 CATCH 块执行。 The connection then gets returned to the pool with the open transaction and the locks are not yet released.然后,连接将通过打开的事务返回到池中,并且锁尚未释放。 Although the transaction will be eventually get rolled back when the pooled connection is reused/reset or closed, the XACT_ABORT setting will cause that to occur immediately and release resource locks.尽管当池连接被重用/重置或关闭时事务最终会回滚,但 XACT_ABORT 设置将导致立即发生并释放资源锁。

Below is the T-SQL transaction management and structured error handling pattern I recommend for most situations.下面是我在大多数情况下推荐的 T-SQL 事务管理和结构化错误处理模式。 Also, note the liberal use of semi-colons to 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');
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM