使用中经常用到@@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脚本

@@Error使用简单小结的更多相关文章

  1. 前台vue的使用简单小结

    前台vue的使用简单小结 本项目要求:安装有node.js 6.0以及以上安装npm使用vue.js官方安装方法初始化项目npm install安装VueResurce:npm install vue ...

  2. springboot微服务的简单小结

    springboot微服务的简单小结 近来公司用springboot微服务,所以小结一下. 基础: 什么是SpingBoot微服务? 如何创建SpringBoot微服务? 如何管理和完善SpringB ...

  3. ASP.NET MVC ViewData/ViewBag 简单小结

    近期在项目中遇到一个问题,就是用ViewBag.Model存储匿名对象传递给View,但是需要根据条件给匿名对象添加属性,这个可真心不易,Google了一下发现很多方案都是动态编译神马的,感觉好高大上 ...

  4. git知识简单小结

    git特点: 1)分布式 2)存储快照而非差异 3)本地有完全的版本库,几乎所有操作都在本地 4)有内在的一致性,SHA1 5)优秀的分支管理 6)支持各种协同模式 7)开源,有一些第三方软件可整合使 ...

  5. SpringMVC_简单小结

    SpringMVC是一个简单的.优秀的框架.应了那句话简单就是美,而且他强大不失灵活,性能也很优秀. 机制:spring mvc的入口是servlet,而struts2是filter(这里要指出,fi ...

  6. log4c 编译安装简单小结(ubuntu12)

    1 下载源码,解压 (假定解压到了当前用户的根目录下,位置是~/log4c-1.2.3) 2 编译安装log4c(指定--prefix极其重要,如果没有指定到/usr下会有一堆麻烦事,还有,不能按照他 ...

  7. 微信小程序支付简单小结与梳理

    前言 公司最近在做微信小程序,被分配到做支付这一块,现在对这一块做一个简单的总结和梳理. 支付,对于购物来说,可以说是占据了十分重要的一块,毕竟能收到钱才是重点. 当然在开发之前,我们需要有下面这些东 ...

  8. 关于Python中的ifelse、while和for循环的简单小结

    1.ifelse 1.1首先简单编辑一个关于ifelse的程序: _username = 'yanfeixu' _password = 'wuyifan' username = input(" ...

  9. java post请求的表单提交和json提交简单小结

    在java实现http请求时有分为多种参数的传递方式,以下给出通过form表单提交和json提交的参数传递方式: public String POST_FORM(String url, Map< ...

随机推荐

  1. php 扩展 redis

    1.通过phpinfo 查看php的版本(  要注意php 是nts 还是ts 通过phpinfo(); 查看其中的 Thread Safety 项,这个项目就是查看是否是线程安全,如果是:enabl ...

  2. Ubuntu12.10 下搭建基于KVM-QEMU的虚拟机环境(十六)

    今天我们继续实验Bridge方式的网络配置. Bridge的逻辑原理图如下: 上图中的“br0”就充当了一个桥的作用,主机上的物理网口eth0等根据需要加入到这个桥里面,所有虚拟机要跟外界通信都通过这 ...

  3. Lockless Ring Buffer Design

    https://www.kernel.org/doc/Documentation/trace/ring-buffer-design.txt Lockless Ring Buffer Design == ...

  4. arp:地址解析协议(Address Resolution Protocol)(来自维基百科)

    地址解析协议(Address Resolution Protocol),其基本功能为通过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行。它是IPv4中网络层必不可少的协议,不过在I ...

  5. C语言统计一个字符串中单词的个数

    假定每一个单词用空格隔开. 样例: 输入:how are you! 输出:3 两种方法: 一: #include <stdio.h> #include <string.h> # ...

  6. 关于pushState

    window.pushState({}, "title", "/index.html");---------------->改变URL的值,但是并不刷新 ...

  7. 【JavaScript】Registering JavaScript object methods as callbacks

    The registration of callback functions is very common in JavaScript web programming, for example to ...

  8. 【JavaScript】jQuery Ajax 实例 全解析

    jQuery确实是一个挺好的轻量级的JS框架,能帮助我们快速的开发JS应用,并在一定程度上改变了我们写JavaScript代码的习惯. 废话少说,直接进入正题,我们先来看一些简单的方法,这些方法都是对 ...

  9. Ubuntu:Target filesystem doesn&#39;t have /sbin/init (Slax 解决)

    计算机(Ubuntu)因为异常断电或是其它原因,再次启动时.非常不幸的出现: Killed mount: mounting /dev on /root/dev failed: No such file ...

  10. 显式参数 VS 隐式参数

    尽量使用显示参数,而不是隐式参数,看下面实例代码. 示例1采用显示参数,示例2采用隐式参数.对于一个不熟悉MonitorManager内部构造的调用者来说,在构造MonitorManager的时候,对 ...