交易是否需要尝试捕获?

Gre*_*Gum 7 t-sql sql-server

我是ac#developer,学习更多TSQL.我写了一个这样的脚本:

begin transaction
--Insert into several tables
end transaction
Run Code Online (Sandbox Code Playgroud)

但我被告知这不是一个好主意,并使用这样的东西:

BEGIN TRANSACTION;

BEGIN TRY
    -- Generate a constraint violation error.
    DELETE FROM Production.Product
    WHERE ProductID = 980;
END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber
        ,ERROR_SEVERITY() AS ErrorSeverity
        ,ERROR_STATE() AS ErrorState
        ,ERROR_PROCEDURE() AS ErrorProcedure
        ,ERROR_LINE() AS ErrorLine
        ,ERROR_MESSAGE() AS ErrorMessage;

    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO
Run Code Online (Sandbox Code Playgroud)

我不明白为什么第二个例子更正确.第一个不会以同样的方式工作吗?似乎第一个要么更新所有表,要么根本不更新?我不明白为什么@@TRANCOUNT在提交之前检查是否有必要.

M.A*_*Ali 4

仅当您位于 try 块内且在实际语句之前才打开事务,并立即提交它,不要等待您的控件转到批处理末尾来提交事务。

一旦你进入 Try 块并且打开了一个事务,如果出现问题,控制将跳转到 CATCH 块,只需在那里回滚你的事务并根据需要进行其他错误处理。

在使用 @@ROWCOUNT 函数实际回滚任何打开的事务的事务检查之前,我添加了一些检查,在这种情况下它并没有多大意义。当您在打开事务之前在 try 块中进行一些验证检查(例如检查参数值和其他内容)并在任何验证检查失败时在 try 块中引发错误时,它会更有用,在这种情况下,控制将跳转到 catch 块甚至无需在那里打开事务,您就可以检查是否有任何打开的事务,如果有任何打开的事务,则回滚。就您的情况而言,您实际上不需要检查任何打开的事务,因为除非事务内部出现问题,否则您不会进入 catch 块。

BEGIN TRY

  BEGIN TRANSACTION 
     -- Multiple Inserts
    INSERT INTO....
    INSERT INTO.... 
    INSERT INTO.... 
 COMMIT TRANSACTION 
    PRINT 'Rows inserted successfully...'

END TRY

BEGIN CATCH 
  IF (@@TRANCOUNT > 0)
   BEGIN
      ROLLBACK TRANSACTION 
      PRINT 'Error detected, all changes reversed'
   END 
    SELECT
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() AS ErrorState,
        ERROR_PROCEDURE() AS ErrorProcedure,
        ERROR_LINE() AS ErrorLine,
        ERROR_MESSAGE() AS ErrorMessage
END CATCH
Run Code Online (Sandbox Code Playgroud)