我有以下代码:
BEGIN TRY
EXEC (@action_sql);
END TRY
BEGIN CATCH
SELECT @change_id AS ChangeId,
@action_sql AS sqlAttempted,
ERROR_MESSAGE () AS ErrorMessage,
ERROR_NUMBER () AS ErrorNumber,
ERROR_SEVERITY () AS ErrorSeverity,
ERROR_LINE () AS ErrorLine;
END CATCH;
IF @@ERROR = 0
BEGIN
PRINT '@@ERROR = ' + CAST (@@ERROR AS VARCHAR (10))
PRINT 'COMMIT';
COMMIT TRANSACTION;
END
ELSE
BEGIN
PRINT '@@ERROR = ' + CAST (@@ERROR AS VARCHAR (10))
PRINT 'ROLLBACK';
ROLLBACK TRANSACTION;
END;
当我在@action_sql
中放入有效或无效的SQL语句时,我总是打印
@@ERROR = 0
COMMIT
即使@@ERROR
无效, action_sql
也始终返回零。
确定是否发生某种错误的最简单方法是什么?
谢谢,
答案 0 :(得分:3)
这是因为@@ERROR
的值重置为0
,即在TRY CATCH
块中捕获并处理后,没有错误。因此,正确的方法是捕获并存储变量中的错误值(如果有),然后根据变量是否表明发生了错误,使用这些变量采取进一步的操作。
请参阅下面的示例代码。 @action_sql
在第一种情况下无效,您将看到打印出的错误代码。在第二种情况下,@action_sql
有效,您将看不到任何打印出的错误代码。
第一个示例:无效@action_sql
。
declare @action_sql NVARCHAR(2000);
declare @change_id INT
declare @ErrorNumber int
declare @ErrorMessage NVARCHAR(2000);
set @action_sql = 'select * from sysobj;'
BEGIN TRY
EXEC (@action_sql);
END TRY
BEGIN CATCH
SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorNumber = ERROR_NUMBER()
-- ERROR_SEVERITY () AS ErrorSeverity,
-- ERROR_LINE () AS ErrorLine;
END CATCH;
IF @ErrorNumber = 0
BEGIN
PRINT '@@ERROR = ' + CAST (@ErrorNumber AS VARCHAR (10))
PRINT 'COMMIT';
--COMMIT TRANSACTION;
END
ELSE
IF (@ErrorNumber > 0)
BEGIN
PRINT '@@ERROR = ' + CAST (@ErrorNumber AS VARCHAR (10))
PRINT 'ROLLBACK';
--ROLLBACK TRANSACTION;
END;
第二个样本:有效@action_sql
declare @action_sql NVARCHAR(2000);
declare @change_id INT
declare @ErrorNumber int
declare @ErrorMessage NVARCHAR(2000);
set @action_sql = 'select top 10 * from sysobjects;'
BEGIN TRY
EXEC (@action_sql);
END TRY
BEGIN CATCH
SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorNumber = ERROR_NUMBER()
-- ERROR_SEVERITY () AS ErrorSeverity,
-- ERROR_LINE () AS ErrorLine;
END CATCH;
IF @ErrorNumber = 0
BEGIN
PRINT '@@ERROR = ' + CAST (@ErrorNumber AS VARCHAR (10))
PRINT 'COMMIT';
--COMMIT TRANSACTION;
END
ELSE
IF (@ErrorNumber > 0)
BEGIN
PRINT '@@ERROR = ' + CAST (@ErrorNumber AS VARCHAR (10))
PRINT 'ROLLBACK';
--ROLLBACK TRANSACTION;
END;
答案 1 :(得分:2)
一旦发生错误,就会填充@@ERROR
函数,并且如果在此函数之后执行任何其他语句,则其值将重置为NULL
,因此您必须使用变量来捕获值执行完陈述后的@@ ERROR函数
因此,要预测错误发生的位置,然后将其值存储到变量中,当你有TRY..CATCH
个阻止时,它实际上是过度杀戮。
由于您正在使用TRY..CATCH
块,因此您根本不需要使用@@ ERROR函数。只需更改代码的顺序。
BEGIN TRY
BEGIN TRANSACTION
EXEC (@action_sql); --<-- if an error occurs here control jumps to catch block and
-- following lines of code never gets executed. (I mean in case of an error)
PRINT 'COMMIT';
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT <> 0 --<-- Once an error occurred check for any open trans
ROLLBACK TRANSACTION -- if there is one ROLLBACK it.
SELECT @change_id AS ChangeId, --<-- Rest of the ERROR Functions
@action_sql AS sqlAttempted,
ERROR_MESSAGE () AS ErrorMessage,
ERROR_NUMBER () AS ErrorNumber,
ERROR_SEVERITY () AS ErrorSeverity,
ERROR_LINE () AS ErrorLine;
END CATCH;
现在,如果您的BEGIN
块中有Explicit Transaction
TRY
,如果发生任何错误,执行将停在那里,控件将跳转到CATCH
块。
然后在那里你可以使用@@TRANCOUNT
检查任何OPEN TRANSACTION,如果打开则回滚它并使用ERROR MESSAGES获取有关错误的所有其他信息。