在SQL Server 2005数据库中进行错误捕捉
在SQL Server数据库中,如果执行Transact-SQL时出现了错误,我们可以使用两种捕捉错误的方法解决此问题,一种是在客户端代码(如c#、delphi等)中使用类似try...catch的语句进行捕捉;另外一种就是在Transact-SQL中利用Transact-SQL本身提供的错误捕捉机制进行捕捉。如果是因为Transact-SQL语句的执行而产生的错误,如键值冲突,使用第一种和第二种方法都可以捕捉,但是如果是逻辑错误,使用客户端代码进行捕捉就不太方便了。因此,本文针对如何使用Transact-SQL进行错误捕捉进行了深入的探讨。
一、非致命错误(non-fatal error)的捕捉
通过执行Transact-SQL而产生的错误可分为两种:致命错误(fatal error)和非致命错误(non-fatal error)。在Transact-SQL中只可以捕捉非致命错误(如键值冲突),而无法捕捉致命错误(如语法错误)。在Transact-SQL中可以通过系统变量@@ERROR判断最近执行的一条语句是否成功执行。如果发生了错误,@@Error的值大于0,否则值为0。下面举一个例子说明@@ERROR的使用。
假设有一个表table1,在这个表中有两个字段f1,f2。其中f1是主键。
INSERT INTO table1 VALUES(1, ''aa'') INSERT INTO table1 VALUES(1, ''bb'') --这条语句将产生一个错误 IF @@ERROR > 0 PRINT ''键值冲突'' |
当执行第二条语句时发生键值冲突错误,@@ERROR被赋为错误号2627,因此输出结果显示''键值冲突''。使用@@ERROR系统变量时需要注意,@@ERROR只记录最近一次执行的Transact-SQL语句所发生的错误,如果最近一次执行的Transact-SQL没有发生错误,@@ERROR的值为0。因此,只能在被捕捉的那条Transact-SQL语句后使用@@ERROR。
在SQL Server中,不仅可以捕捉系统提供的错误,还可以自定义错误。有两种方法可以定义错误信息。
1. 使用sp_addmessage系统存储过程添加错误信息,然后使用RAISERROR抛出错误
sp_addmessage将错误号,错误级别、错误描述等信息添加到系统表中,然后使用RAISERROR根据相应的错误号抛出错误信息。用户自定义的信息应该从50001开始。
EXEC sp_addmessage @msgnum = 50001, @severity = 16, @msgtext = ''sql encounter an error(%s).'', @lang = ''us_english'' EXEC sp_addmessage @msgnum = 50001, @severity = 16, @msgtext = ''sql遇到了一个错误(%1!).'' |
如果使用的SQL Server版本是非英语版本,在添加本地错误信息时必须首先添加英文的错误信息。错误描述可以象c语言中的printf的格式字符串一样使用参数,如%s、%d。但要注意的是在英文版的错误信息中要使用%s、%d等形式,而在本地化的错误信息中要使用%1!、%2!等形式,在每个%?(1 <= ? <= n)后需要加一个!,而且%?的数目必须和英文版的错误信息的参数一致。
在未插入本地化错误信息时,RAISERROR将使用英文版的错误信息。当插入本地化错误信息时,RAISERROR使用本地化的错误信息。
RAISERROR(50001, 16, 1, ''测试'')
输出的结果:
服务器: 消息 50001,级别 16,状态 1,行 1
sql遇到了一个错误(测试).
其中''测试''字符串通过%1传入本地化的错误描述字符串中。
2.直接使用RAISERROR将错误抛出
使用第一种方法虽然使Transact-SQL语句看上去更整洁(这种方法类似于在编程语言中使用常量定义错误信息,然后在不同的地方通过错误编号引用这些错误信息。),但是这样做却使错误信息和数据库的耦合度增加,因为如果将这些带有RAISERROR的Transact-SQL放到别的SQL Server数据库上执行,由于在其它的数据库中还未添加错误信息,因此会产生RAISERROR调用错误,除非使用sp_addmessage将所需的错误信息再加入到其它的数据库中。
基于上述原因,RAISERROR不仅可以根据错误代码抛出错误信息,也可以直接通过错误描述格式字符串抛出错误信息。
RAISERROR(''sql遇到了一个错误(%s)'', 16, 1, ''测试'')
二、逻辑错误的捕捉
在实际应用中,更多的是由于某些业务要求而产生的逻辑错误。这些错误无法通过@@ERROR进行捕捉。如果使用客户端代码进行捕捉,那么Transact-SQL必须一条一条地执行。如果使用存储过程,那么发生在存储过程内部的逻辑错误就很难在客户端代码中进行捕捉,因此,下面将讨论如何使用Transact-SQL捕捉逻辑错误。
所谓逻辑错误,就是在执行完Transact-SQL后,执行结果与业务要求的结果不符而产生的。为了说明如何处理逻辑错误,我们再建立一个表table2,这个表的结构和table1完全一样,只是f1字段不再是主键了。然后建立一个存储过程,它的功能是在table1和table2中同时插入一条记录,但是这条记录必须满足两个条件。
1.f1值不能大于100
2.要插入的记录在table1中不存在,如果存在,在table1和table2中都不插入这条记录
CREATE PROCEDURE p1(@Num int) AS DECLARE @Error int, @RowCount int BEGIN TRANSACTION INSERT INTO table2 VALUES(@Num, ''p'') IF @Num > 100 BEGIN RAISERROR(''%s的值不能大于100。'', 16, 1, ''@Num'') ROLLBACK TRANSACTION RETURN 1 END ELSE BEGIN SELECT f1 FROM table1 WHERE f1 = @Num IF @@ROWCOUNT > 0 BEGIN RAISERROR(''table1中已经存在%d了。'', 16, 1, @Num) ROLLBACK TRANSACTION RETURN 2 END ELSE BEGIN INSERT INTO table1 VALUES(@Num, ''p'') COMMIT TRANSACTION RETURN 0 END END |
在这个存储过程中一开始使用BEGIN TRANSACTION显示地开始一个事务,然后当上述两种错误发生时使用ROLLBACK TRANSACTION恢复到初始状态,如果成功插入,使用COMMIT TRANSACTION提交改变。可以通过如下语句进行调用。
DECLARE @ErrNum int EXEC @ErrNUm = p1 2 PRINT @ErrNum |
可以通过@ErrNum得到p1返回的错误代码,如果返回0,表示执行成功。
SQL Server 2005数据库中错误捕捉的新功能
虽然在以前的SQL Server版本中可以通过一些技巧实现错误捕捉,但有时需要增加一些额外的开销,如在p1中使用了SELECT语句。庆幸的是在SQL Server2005中提供了和大多数编程语言类似的try...catch错误捕捉功能,从而使Transact-SQL第一次可以真正地进行错误捕捉。使用try...catch可以将p1的下半部分改写为如下形式。
ELSE BEGIN BEGIN TRY INSERT INTO table1 VALUES(@Num, ''p'') COMMIT TRANSACTION RETURN 0 END TRY BEGIN CATCH RAISERROR(''table1中已经存在%d了。'', 16, 1, @Num) ROLLBACK TRANSACTION RETURN 2 END CATCH END |
我们可以发现,这个改写的部分未使用SELECT查询table1中是否已经有了某条记录,而是通过数据库的约束来进行判断的。如果键值冲突,就产生了错误,这样SQL语句就直接跳到BEGIN CATCH中执行错误处理代码。这样做效率要比上一个版本高得多,而且如果将RAISERROR去掉,p1就不会抛出任何错误,只是返回了一个错误码,这种做法的好处是有利于客户端代码进行处理。
如果使用SQL Server 2005数据库,在Transact-SQL中进行错误捕捉,建议尽量使用try...catch,因为它会捕捉到未预料到的错误,并且会使Transact-SQL更易于维护。当然,这样做就无法将Transact-SQL移植到SQL Server2000或更低的版本上运行,如果想写通用的Transact-SQL,读者可以使用传统的方法来捕捉错误。
<script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/buttonLite.js#style=-1&uuid=&pophcol=3&lang=zh"></script> <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/bshareC0.js"></script>
阅读(267) | 评论(0) | 转发(0) |
上一篇:批处理计算前N个月第一天的日期
下一篇:会员注册时手机号码异步验证的JS代码
- ABAP文章索引
- 数据库课程设计报告(仓库管理...
- 拼音汉字对照表
- sql isnull函数的使用
- 数据挖掘电子书下载
- cpu %和load average是怎样的...
- 如何确定线程使用的端口...
- mysql整形数据类型插入0001数...
- weblogic集群下启动服务有一个...
- nagios pnp 报错
在SQL Server 2005数据库中进行错误捕捉相关推荐
- 解决SQL Server 2005数据库中datetime时间字段在前端显示时分秒的问题
SQL Server 2005中时间类型datetime的格式是"年月日时分秒",直接读出来该字段,为了不让它在前端显示"时分秒"若是显示在dataGridVi ...
- 20110125 学习记录:在SQL Server 2005数据库中修改存储过程
我农民了,在sqlserver2005里面修改了存储过程后居然不知道咋保存... 因为一保存就相当于save as为本地文件了 查了一下,简单的要死,只要把修改后的存储过程execute一下就ok了~ ...
- SQL Server 2005数据库日志文件损坏的情况下如何恢复数据库
在某些偶然的情况下,会引起SQL Server 2005数据库日志文件的损坏,比如:硬件故障.计算机非正常重启或关机. 当SQL Server 2005数据库日志文件损坏时,可能会出现以下情况: 1. ...
- SQL SERVER 2005数据库镜像搭建
SQL SERVER 2005数据库镜像搭建 一 概述 数据库镜像是SQL SERVER 2005用于提高数据库可用性的新技术.数据库镜像将事务日志记录直接从一台服务器传输到另一台服务器,并且能够在出 ...
- SQL SERVER 2005 数据库状态为“可疑”的解决方法(转)
SQL SERVER 2005 数据库状态为"可疑"的解决方法(转) 2010-01-04 15:10 在被设置为"可疑"后很纳闷,之前没有遇到此类情况,问了几 ...
- SQL SERVER 2005 数据库状态为“可疑”的解决方法
重启服务 -------------------------------------------------- 日志文件丢了,建一个日志文件 ----------------------------- ...
- 烂泥:SQL Server 2005数据库备份与恢复
本文首发于烂泥行天下. 服务器的迁移,因为业务使用的数据库是SQL Server 2005,所以就要首先对数据库进行备份. 备份可以分为手动备份和自动备份,我们先来介绍手动备份. 打开SQL Serv ...
- SQL Server 2005 数据库邮件 使用要点
1 利用SQL Server 2005数据库邮件,首先启用数据库邮件服务, 如下:打开SQL Server"配置工具"中的"外围应用配置器",选择"功 ...
- Eclipse如何连接SQL Server 2005数据库
做管理系统当然少不了经常与数据库打交道,在网上搜了很多数据库版本都不小,大的有好几个G的,小的也有几百兆的,我这可怜的内存,最终找了个精简版中的精简版的Sql server2005,只有80几兆,本来 ...
最新文章
- lvm讲解和磁盘故障案例
- 【超详细】DBCP连接池配置参数说明
- python怎么输出图像测试_python pyautogui-不检测图像时的位置打印问题
- linux下解压大于4G文件提示error: Zip file too big错误的解决办法
- 如何用ABAP代码的方式在短时间内批量生成大量订单数据用于性能测试
- python binascii array('c')_详解Python中的array数组模块相关使用
- 牛客网-数据结构笔试题目(三)-博弈论圆圈游戏(Circle Game)(附源码)
- [css] 说说你对css盒子模型的理解
- .Net中的多态知识点
- RHEL5-4的启动流程介绍
- PHP_TP5框架开发后端接口(代码编写思路)
- 【Flink】Direct buffer memory taskmanager.memory.task.off-heap.size
- Linux学习总结(74)——wget 命令详解
- 嵌入式工作笔记0003---认识LCD显示器
- linux中判断语句,Linux--shel的if判断语句--05
- 凸优化第三章凸函数 作业题
- 未来的计算机没有显示屏,不吹也不黑 解析未来显示的四种可能!
- vue 关于图片和文字的绝对定位 js 动态设置定位
- head和tail命令--用Enki学Linux系列(8)
- 怎么调大计算机浏览器内字体,W7系统浏览器字体大小设置的方法