use*_*839 47 sql sql-server transactions exception try-catch
我正在尝试编写一个具有事务和try/catch块的MS sql脚本.如果它捕获异常,则回滚事务.如果不是,则提交事务.我看过几个不同的网站说这样做:
begin transaction
begin try
--main content of script here
end try
begin catch
rollback transaction
end catch
commit transaction
Run Code Online (Sandbox Code Playgroud)
但即使在捕获异常的情况下,我们仍然不会点击"提交事务"行吗?这不会导致SQL错误,因为事务已经回滚了吗?我认为应该这样做:
declare @success bit = 1
begin transaction
begin try
--main content of script here
end try
begin catch
rollback transaction
set @success = 0
end catch
if(@success = 1)
begin
commit transaction
end
Run Code Online (Sandbox Code Playgroud)
普遍发布的解决方案如何不包含@success变量?提交已经回滚的事务是否没有发生sql错误?我是否错误地说在捕获异常的情况下仍然会遇到第一个代码示例的"提交事务"行?
Gar*_*ker 71
我一直认为这是关于这个主题的更好的文章之一.它包括以下示例,我认为它清楚,并包括经常被忽视的@@ trancount,这是可靠的嵌套事务所需要的
PRINT 'BEFORE TRY'
BEGIN TRY
BEGIN TRAN
PRINT 'First Statement in the TRY block'
INSERT INTO dbo.Account(AccountId, Name , Balance) VALUES(1, 'Account1', 10000)
UPDATE dbo.Account SET Balance = Balance + CAST('TEN THOUSAND' AS MONEY) WHERE AccountId = 1
INSERT INTO dbo.Account(AccountId, Name , Balance) VALUES(2, 'Account2', 20000)
PRINT 'Last Statement in the TRY block'
COMMIT TRAN
END TRY
BEGIN CATCH
PRINT 'In CATCH Block'
IF(@@TRANCOUNT > 0)
ROLLBACK TRAN;
THROW; -- raise error to the client
END CATCH
PRINT 'After END CATCH'
SELECT * FROM dbo.Account WITH(NOLOCK)
GO
Run Code Online (Sandbox Code Playgroud)
Jim*_* V. 30
在你的第一个例子中,你是对的.无论try块是否触发,批处理都将命中提交事务.
在你的第二个例子中,我同意其他评论者的观点.使用成功标志是不必要的.
我认为以下方法基本上是一种轻量级的最佳实践方法.
如果要查看它如何处理异常,请将第二个插入的值从255更改为256.
CREATE TABLE #TEMP ( ID TINYINT NOT NULL );
INSERT INTO #TEMP( ID ) VALUES ( 1 )
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO #TEMP( ID ) VALUES ( 2 )
INSERT INTO #TEMP( ID ) VALUES ( 255 )
COMMIT TRANSACTION
END TRY
BEGIN CATCH
DECLARE
@ErrorMessage NVARCHAR(4000),
@ErrorSeverity INT,
@ErrorState INT;
SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
RAISERROR (
@ErrorMessage,
@ErrorSeverity,
@ErrorState
);
ROLLBACK TRANSACTION
END CATCH
SET NOCOUNT ON
SELECT ID
FROM #TEMP
DROP TABLE #TEMP
Run Code Online (Sandbox Code Playgroud)
我在 ms sql 脚本模式下成功使用了几次,它使用了Try-Catch、Commit Transaction - Rollback Transaction、Error Tracking。
您的 TRY 块将如下所示
BEGIN TRY
BEGIN TRANSACTION T
----
//your script block
----
COMMIT TRANSACTION T
END TRY
Run Code Online (Sandbox Code Playgroud)
您的 CATCH 块将如下所示
BEGIN CATCH
DECLARE @ErrMsg NVarChar(4000),
@ErrNum Int,
@ErrSeverity Int,
@ErrState Int,
@ErrLine Int,
@ErrProc NVarChar(200)
SELECT @ErrNum = Error_Number(),
@ErrSeverity = Error_Severity(),
@ErrState = Error_State(),
@ErrLine = Error_Line(),
@ErrProc = IsNull(Error_Procedure(), '-')
SET @ErrMsg = N'ErrLine: ' + rtrim(@ErrLine) + ', proc: ' + RTRIM(@ErrProc) + ',
Message: '+ Error_Message()
Run Code Online (Sandbox Code Playgroud)
您的 ROLLBACK 脚本将成为 CATCH 块的一部分,如下所示
IF (@@TRANCOUNT) > 0
BEGIN
PRINT 'ROLLBACK: ' + SUBSTRING(@ErrMsg,1,4000)
ROLLBACK TRANSACTION T
END
ELSE
BEGIN
PRINT SUBSTRING(@ErrMsg,1,4000);
END
END CATCH
Run Code Online (Sandbox Code Playgroud)
在不同的脚本块之上,您需要将其用作一个块。如果在TRY块中发生任何错误,它将转到CATCH块。在那里设置有关错误编号、错误严重性、错误行等的各种详细信息。最后,所有这些细节都将附加到@ErrMsg 参数中。然后它会检查事务的计数 (@@TRANCOUNT >0) ,即事务中是否有任何用于回滚的内容。如果存在,则显示错误消息和ROLLBACK TRANSACTION。否则只需打印错误消息。
我们将COMMIT TRANSACTION T脚本保留在 TRY 块的最后一行,以确保只有在 TRY 块中的所有代码都成功运行后才应提交事务(数据库中的最终更改)。
归档时间: |
|
查看次数: |
90992 次 |
最近记录: |