如何确保所有SQL更新都已执行

时间:2018-12-05 18:49:06

标签: sql-server

我们在生产环境中遇到了一个问题,其中只有前2个更新运行,而后2个没有运行。从BIDS(SQL服务器)运行以下脚本以确保运行4个sql更新语句中的每一个,我们可以实现什么?我们是否需要将整个内容包装在Try ..... Catch中?

下面基本上是我现在在生产中使用的最终工作代码。

SET XACT_ABORT ON;
GO

BEGIN TRANSACTION

-- Batch 0
BEGIN TRY

    --There is a step prior to this step to delete table
    Insert Into Table X (Field1, Field2, Field3)

    Select
            Field1
            ,Field2
            ,Field3
    FROM Table Loans

END TRY
BEGIN CATCH
  PRINT 'Error Number: ' + str(error_number()) ;
  PRINT 'Line Number: ' + str(error_line());
  PRINT error_message();
  ROLLBACK TRANSACTION;
END CATCH;
GO

-- Batch 1
BEGIN TRY
  -- Rollback transaction if error occurred
  IF (XACT_STATE()) = -1
  BEGIN
    RAISERROR('The transaction is in an uncommittable state. Rolling back transaction.', 18, 3);
  END;

  -- Do not continue if the transaction was rolled back
  IF (XACT_STATE()) = 0
  BEGIN
    RAISERROR('The transaction was rolled back.', 18, 1);
  END;

  --Update A Fields
    Update X Table
    Set X Field4 = A Field
    From X Table
    Left OUTER JOIN A Table
        ON X Key = A Key

END TRY
BEGIN CATCH
  PRINT 'Error Number: ' + str(error_number()) ;
  PRINT 'Line Number: ' + str(error_line());
  PRINT error_message();
  IF (XACT_STATE()) <> 0
  BEGIN
    PRINT 'Rolling Back Transaction...';
    ROLLBACK TRANSACTION;
  END;
END CATCH;
GO

-- Batch 2
BEGIN TRY
  -- Rollback transaction if error occurred
  IF (XACT_STATE()) = -1
  BEGIN
    RAISERROR('The transaction is in an uncommittable state. Rolling back transaction.', 18, 3);
  END;

  -- Do not continue if the transaction was rolled back
  IF (XACT_STATE()) = 0
  BEGIN
    RAISERROR('The transaction was rolled back.', 18, 1);
  END;

  --Update B Fields
    Update X Table
    Set X Field5 = B Field
    From X Table
    Left OUTER JOIN B Table
        ON X Key = B Key

END TRY
BEGIN CATCH
  PRINT 'Error Number: ' + str(error_number()) ;
  PRINT 'Line Number: ' + str(error_line());
  PRINT error_message();
  IF (XACT_STATE()) <> 0
  BEGIN
    PRINT 'Rolling Back Transaction...';
    ROLLBACK TRANSACTION;
  END;
END CATCH;
GO

-- Batch 3
BEGIN TRY
  -- Rollback transaction if error occurred
  IF (XACT_STATE()) = -1
  BEGIN
    RAISERROR('The transaction is in an uncommittable state. Rolling back transaction.', 18, 3);
  END;

  -- Do not continue if the transaction was rolled back
  IF (XACT_STATE()) = 0
  BEGIN
    RAISERROR('The transaction was rolled back.', 18, 1);
  END;

  --Update C Fields
    Update X Table
    Set X Field5 = C Field
    From X Table
    Left OUTER JOIN C Table
        ON X Key = C Key

END TRY
BEGIN CATCH
  PRINT 'Error Number: ' + str(error_number()) ;
  PRINT 'Line Number: ' + str(error_line());
  PRINT error_message();
  IF (XACT_STATE()) <> 0
  BEGIN
    PRINT 'Rolling Back Transaction...';
    ROLLBACK TRANSACTION;
  END;
END CATCH;
GO

-- Batch 4
BEGIN TRY
  -- Rollback transaction if error occurred
  IF (XACT_STATE()) = -1
  BEGIN
    RAISERROR('The transaction is in an uncommittable state. Rolling back transaction.', 18, 3);
  END;

  -- Do not continue if the transaction was rolled back
  IF (XACT_STATE()) = 0
  BEGIN
    RAISERROR('The transaction was rolled back.', 18, 1);
  END;

  --Update D Fields
    Update X Table
    Set X Field7 = D Field
    From X Table
    Left OUTER JOIN D Table
        ON X Key = D Key

END TRY
BEGIN CATCH
  PRINT 'Error Number: ' + str(error_number()) ;
  PRINT 'Line Number: ' + str(error_line());
  PRINT error_message();
  IF (XACT_STATE()) <> 0
  BEGIN
    PRINT 'Rolling Back Transaction...';
    ROLLBACK TRANSACTION;
  END;
END CATCH;
GO

-- Commit transaction
IF XACT_STATE() = 1
BEGIN
  COMMIT TRANSACTION;
  PRINT 'Transaction committed.';
END;

2 个答案:

答案 0 :(得分:2)

我会将其包装在事务中,如果出现问题,它将自动回滚更改。

BEGIN TRANSACTION
    your tsql code...
COMMIT

在仍在使用事务的同时,将代码包装在try / catch中,然后可以选择/打印/记录错误。 Try...Catch (Transact-SQL)

答案 1 :(得分:1)

这一切都取决于您的生产环境如何处理服务器错误。

例如,如果第3次更新由于外键冲突而失败,则服务器将错误返回给客户端。客户处理它,但是它处理它。 中止,重试或忽略情况。根据实际问题,该批处理不一定要终止,因此,除非客户端采取行动,否则仍然可能执行第4次更新。

服务器还会将每个存储过程的退出状态返回给客户端,客户端可以自由地接受或忽略该退出状态。您也可以将整个内容包装在存储过程中。在每个UPDATE之后,测试@@error,然后返回是否已设置。

如果您的生产环境完全未知或不可靠,则可以调用自己的存储过程,并将其名称和返回状态写到另一个表中,可能还包括执行时间。然后,您可以查询该表以查看它是否成功。