@@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脚本

时间: 2024-10-14 10:01:48

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

软件导论第五周作业-------简单小结

简单小结: 一.JDBC简介 JDBC全称Java Data Base Connectivity(java数据库连接),可以为多种数据库提供统一的访问,是连接Java应用程序和数据库的桥梁,有了JDBC,Java就可以从数据库中读取.存储数据 二.JDBC编程步骤 1.加载驱动程序Class.forName(driverClass); 加载Mysql驱动:Class.forName("com.mysql.jdbc.Driver"); 加载Oracle驱动:Class.forName(&

ASP.NET MVC ViewData/ViewBag 简单小结

近期在项目中遇到一个问题,就是用ViewBag.Model存储匿名对象传递给View,但是需要根据条件给匿名对象添加属性,这个可真心不易,Google了一下发现很多方案都是动态编译神马的,感觉好高大上,最后也没采用,因为不知道动态编译的性能消耗大不大. 最后是自己简单研究了一下,在ViewBag.Model中存储了Dictionary<string, object>,在View通过Model[key]的方式可以正常读取相应的值,在此对ViewData和ViewBag的使用进行一个简单的小结:1

藏地传奇真言专题简单小结

先来个传送门:藏地传奇-真言专题.话说搞这个专题也折腾了不少时间,看似简单的页面,实际也隐藏着大大小小的坑.下面请听我一一道来. 一.先从布局说起 真言专题页采用的布局是屡见不鲜的瀑布流.其实当时一接到这个需求的时候,第一反应是Github上搜插件库,因为关于瀑布流的JQ库实在是太多了.像KISSY的waterfall,像@Sebobo 的Wookmark-jQuery,像jQuery Masonry等,都是很简单易用的库.但体验过其中几个DEMO之后,发现其实都不符合需求的预期,于是决定自己写

Android的Message机制(简单小结)

对于Android的Message机制主要涉及到三个主要的类,分别是Handler.Message.Looper:首先对每个类做一个简单介绍:然后再介绍所谓的Android的Message机制是如何实现的,最后给了一个示例. 一.介绍三个相关的类 1. Handler主要有两个用途:首先是可以定时处理或者分发消息,其次是可以添加一个执行的行为在其它线程中执行, 对于Handler中的方法,可以选择你关心的操作去覆盖它,处理具体的业务操作,常见的就是对消息的处理可以覆盖public voidhan

简单小结几个常见算法的大体实现思想

前言,今天笔试一题,只做了最后一题(输入A,B两字符串,比较是否相等).N年没有笔试了,想起一些还记的算法小结下. PS,想了几种,最后选择先建二叉查找树,再中序查找得有序字符,后循环比较方式. 排序 1.冒泡:从低往上选择临近比较排序: 2.插入:在剩下要排序数据中,选一个按顺序插入: 3.选择:在剩下要排序数据中,选个最值(最大或最小)插入: 4.快速:选择一参照值,从右左两边不断各自向对方移动.与查找值比大小,后交换值: 5.合并:先拆成有序,再比较合并: 6.堆排序:先建堆(上对于下),

WUST暑假集训第一周简单小结

目录 一.dfs序在树状图中的经典应用 二.初探双向广度优先搜索 三.整体二分思想完美解决kth number问题 四.实战模拟退火思想(变步长贪心算法) 五.凸包问题经典例题 六.树的重心问题经典例题 七.矩阵快速幂例题 一.dfs序在树状图中的经典应用 首先是dfs序的问题,什么是dfs序? 我的理解:dfs序也就是将一棵树通过树的遍历顺序将一棵树转化为父节点包含了子节点的序列,n个结点的树对应n个数的序列,一个结点在序列中的表现形式为一段区间,这段区间中包含了该结点的子树区间,且构造的区间

VS2008中的配置文件app.config简单小结

应用程序的配置文件用于读取和保存简单的本地数据,vs中新增配置文件可以直接在项目的”属性“-”设置“里添加,添加后在项目的Properties文件夹会多出一组两个文件:Settings.settings和Settings.Designer.cs,前者是一个xml文件用于vs界面的显示,后者是一个vs生成的继承了System.Configuration.ApplicationSettingsBase的类Setting,该类是强类型化的,因此可以方便地通过代码读取和保存配置项: 另外,也可以右键”项

This week 知识点的简单小结

1,显示身份证中间中间用点点点的验证!例如: var idcontent = $("#idnumber").text(); var ccc = idcontent.replace(/^(.{6})(?:\d+)(.{4})$/, "$1****$2"); $("#idnumber").text(ccc); 2,声明不连续数组,例如: var state = ["未支付", "已支付", "未评价&

UIPickerView 简单小结

一.UIPickerView 1.UIPickerView的常见属性 // 数据源(用来告诉UIPickerView有多少列多少行) @property(nonatomic,assign) id<UIPickerViewDataSource> dataSource; // 代理(用来告诉UIPickerView每1列的每1行显示什么内容,监听UIPickerView的选择) @property(nonatomic,assign) id<UIPickerViewDelegate>