[转]在SQL Server2005中进行不当捕捉

原文:http://www.cnblogs.com/nokiaguy/archive/2008/05/09/1190551.html

   任何程序还或出现错误,在SQL
Server中执Transact-SQL也未例外。如果以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 Server2005中破绽百出捕捉的新职能
    虽然在原先的SQL
Server版本中可由此一些技实现错误捕捉,但奇迹需要充实部分格外的开发,如以p1中以了SELECT语句。庆幸的凡在SQL
Server2005中提供了同多数编程语言类的try…catch错误捕捉功能,从而使Transact-SQL第一糟糕可真正地进行不当捕捉。使用try…catch可以以p1的下半部分改写为如下形式。

图片 1
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就无见面废弃来其它不当,只是返回了一个错误码,这样方便客户端代码进行处理。
    在Transact-SQL中开展不当捕捉,如果运用的凡SQL
Server2005,我的建议是尽可能用try…catch,因此它们会捕捉到未预料到的错误,并且会使Transact-SQL更易保障。当然,这样做就是无法拿Transact-SQL移植到SQL
Server2000或又小之版及运行,要是想写通用的Transact-SQL,还是用传统的法子捕捉错误吧!

相关文章