• @@Error使用简单小结


     使用中经常用到@@Error来判断上一个语句是否执行成功,对此小结一下,可能有些不准确,欢迎指出。

    1.1  介绍

    SQL SERVER 中@@表示系统全局变量

    (1)   返回执行的上一个 Transact-SQL 语句的错误号,如果执行没有错误,则返回 0 。

    (2)   如果错误是 sys.messages 目录视图中的错误之一,则 @@ERROR 将包含 sys.messages.message_id 列中表示该错误的值。  可以在 sys.messages 中查看与 @@ERROR 错误号相关的文本信息。

    (3)   由于 @@ERROR 在每一条语句执行后被清除并且重置,因此应在语句验证后立即查看它,或将其保存到一个局部变量中以备以后查看。

    1.2  范例及使用

    (1)  分析执行SQL出现错误,后续脚本的执行情况

    执行语句:

    UPDATE tbOrder SET OrderNo = '201605010008' WHERE OrderNo = '201605010001'

    --执行上一步出现外键约束错误,并且继续执行下一步(547为约束错误)

    PRINT @@ERROR  --输出错误号

    UPDATE tbOrder SET OrderAmount = 'ABC' WHERE OrderNo = '201605010001'

    --在执行上一步时出现类型异常,并且不执行下面的步骤

    PRINT @@ERROR  --未输出

    说明:第1个SQL出错后,仍然执行了后面的代码,输出了@@Error错误号,第2个SQL出错后直接终止后续执行。

    说明执行SQL出现错误后,有的错误会直接终止后续执行,有的出现错误后仍然可以继续执行后续脚本

    (2)  查询成功后,系统变量@@Error变为0

     执行语句:

    DELETE FROM tbOrder WHERE OrderNo = '201605010001'

    PRINT 'Delete: ' + CAST(@@ERROR AS VARCHAR(20))   --输出

    SELECT 1  

    PRINT 'Select: ' + + CAST(@@ERROR AS VARCHAR(20))  --输出 Select:0 

    说明:执行SQL 成功后,@@Error参数被设置为0

    (3)  通过Try Catch捕获错误,输出@@Error

    a)  还是上面的删除操作,产生外键约束问题

    执行语句:

    BEGIN TRY

        DELETE FROM tbOrder WHERE OrderNo = '201605010001'

        PRINT 'DELETE ' + CAST(@@ERROR AS VARCHAR(20))   --没有输出

    END TRY

    BEGIN CATCH

        PRINT 'CATCH ' + CAST(@@ERROR AS VARCHAR(20))

        PRINT ERROR_MESSAGE()

        PRINT ERROR_SEVERITY()

        PRINT ERROR_STATE()

    END CATCH

    GO

    输出结果:

     

    b)  还是上面的更新操作,产生错误,不执行后续代码

    执行语句:

    BEGIN TRY

        UPDATE tbOrder SET OrderAmount = 'ABC' WHERE OrderNo = '201605010001'

        PRINT 'UPDATE ' + CAST(@@ERROR AS VARCHAR(20))

    END TRY

    BEGIN CATCH

        PRINT 'CATCH ' + CAST(@@ERROR AS VARCHAR(20))

        PRINT ERROR_MESSAGE()

        PRINT ERROR_SEVERITY()

        PRINT ERROR_STATE()

    END CATCH

    GO

    输出结果:

     

    说明:在Try中执行SQL产生错误后,直接被Catch捕获,Try中后续代码终止执行,直接执行Catch中的代码

    (4)  测试有事物的操作是否产生错误后都回滚

    a)  直接增加事物

    执行脚本:

    BEGIN TRAN

        --执行正常

        INSERT INTO dbo.tbOrderDetail( OrderNo, ProductID, Quantity, Price )

           VALUES  ( '201605010001',50,200,10)

        --执行报错

        DELETE FROM tbOrder WHERE OrderNo = '201605010001'

        PRINT 'DELETE: ' +  CAST(@@ERROR AS VARCHAR(20))

    COMMIT TRAN

    执行结果(同时查询订单明细):

     

    说明:执行出错后,前面执行的插入操作数据并没有回滚,说明直接增加事物并不能回滚出错前的数据

    b)  增加@@Error判断执行是否成功

    执行脚本:

    BEGIN TRAN

        --执行正常

        INSERT INTO dbo.tbOrderDetail( OrderNo, ProductID, Quantity, Price )

           VALUES  ( '201605010001',50,200,10)

        IF @@ERROR <> 0

        BEGIN

           ROLLBACK TRAN

           RETURN

        END

        --执行报错

        DELETE FROM tbOrder WHERE OrderNo = '201605010001'

        --UPDATE tbOrder SET OrderAmount = 'ABC' WHERE OrderNo = '201605010001'   --将Delete操作换成更新操作产生异常后事物也会回滚

        IF @@ERROR <> 0

        BEGIN

           ROLLBACK TRAN

           RETURN

        END

    COMMIT TRAN

    执行结果(同时查询订单明细):

     

    说明:增加@@Error判断,执行错误时前面的数据都回滚了。同时将语句中的Delete操作换成执行已屏蔽的更新操作产生异常后,事物同样也会回滚

    (5)  通过设置XACT_ABORT,测试出现错误整个事物是否回滚

    备注:当 SET XACT_ABORT 为 ON 时,如果执行 Transact-SQL 语句产生运行时错误,则整个事务将终止并回滚。

    当 SET XACT_ABORT 为 OFF 时,有时只回滚产生错误的 Transact-SQL 语句,而事务将继续进行处理。如果错误很严重,那么即使 SET XACT_ABORT 为 OFF,也可能回滚整个事务。OFF 是默认设置。

    a)  XACT_ABORT 为 OFF,只有执行出错的回滚

    执行脚本:

    SET XACT_ABORT OFF

    BEGIN TRAN

        --执行正常

        INSERT INTO dbo.tbOrderDetail( OrderNo, ProductID, Quantity, Price )

           VALUES  ( '201605010001',50,200,10)

        --执行报错

        DELETE FROM tbOrder WHERE OrderNo = '201605010001'

        PRINT 'DELETE: ' +  CAST(@@ERROR AS VARCHAR(20))

        --执行正常

        INSERT INTO dbo.tbOrderDetail( OrderNo, ProductID, Quantity, Price )

           VALUES  ( '201605010001',51,10,100)

       

    COMMIT TRAN

    执行结果(同时查询明细):

     

    b)  XACT_ABORT 为 ON,强制整个事物回滚

    执行脚本:

    SET XACT_ABORT ON

    BEGIN TRAN

        --执行正常

        INSERT INTO dbo.tbOrderDetail( OrderNo, ProductID, Quantity, Price )

           VALUES  ( '201605010001',50,200,10)

        --执行报错

        DELETE FROM tbOrder WHERE OrderNo = '201605010001'

        PRINT 'DELETE: ' +  CAST(@@ERROR AS VARCHAR(20))

    COMMIT TRAN

    SET XACT_ABORT OFF

    执行结果(同时查询明细):

     

    说明:设置XACT_ABORT为OFF(默认为OFF),只有执行出错的语句回滚了,其他的没有回滚数据;设置XACT_ABORT为ON时,当执行SQL产生错误后,强制整个事物回滚,并且不在执行后续代码

    (6)  通过Try Catch捕获错误,显示事物执行错误,并回滚

    执行脚本:

    BEGIN TRAN

        BEGIN TRY

        --执行正常

        INSERT INTO dbo.tbOrderDetail( OrderNo, ProductID, Quantity, Price )

           VALUES  ( '201605010001',50,200,10)

       

        --执行报错

        DELETE FROM tbOrder WHERE OrderNo = '201605010001'

        --UPDATE tbOrder SET OrderAmount = 'ABC' WHERE OrderNo = '201605010001'

       

        COMMIT TRAN

       

    END  TRY

    BEGIN CATCH

        PRINT '执行错误' + CAST(@@ERROR AS VARCHAR(20))

        PRINT ERROR_MESSAGE()

        PRINT ERROR_SEVERITY()

        PRINT ERROR_STATE()

        ROLLBACK TRAN --必须增加回滚,否则事物会一直挂死在哪里

    END CATCH

    执行结果(同时查询订单明细):

     

    1.3  总结说明

    参照上面的使用演示及结果,可以由如下3种处理方式确保数据完整性

    (1) 通过@@Error判断来语句是否执行成功,是否事物需要回滚(参见1.2 (4) )

    (2) 设置XACT_ABORT为ON,强制整个事物执行出错时都回滚 (参见1.2 (5) )

    (3) 通过Try Catch捕获执行异常,并回滚事物 (参见1.2 (6) )

    1.4  参考资料

     微软官网解释

    https://msdn.microsoft.com/zh-cn/library/ms188790.aspx

    try catch 捕获不到的一些错误及解决方法

    http://blog.csdn.net/kk185800961/article/details/40043415

    事务执行情况跟踪分析

    http://blog.csdn.net/zhaowenzhong/article/details/16342843

    1.5  相关附件

     相关SQL脚本

  • 相关阅读:
    Java泛型学习笔记
    Java泛型学习笔记
    Java泛型学习笔记
    Java泛型学习笔记
    Java泛型学习笔记
    Java泛型学习笔记
    Java泛型学习笔记
    有1到100共100个数, 从1开始, 每隔1, 2, 3... 个数拿走一个数, 最后剩下几?(约瑟夫环)
    推荐一个自动抽取pdf高亮笔记的web应用
    协程
  • 原文地址:https://www.cnblogs.com/johden2/p/5482410.html
Copyright © 2020-2023  润新知