SQL Server的Exception Handling

[ 来源:http://www.it55.com | 作者: | 时间:2007-12-18 | 收藏 | 推荐 ] 【


  INSERT INTO dbo.T_USERS
   ([USER_ID]
   ,[USER_NAME]
   ,LOWERED_USER_NAME)
   VALUES(@user_id, @user_name, LOWER(@user_name))
  SET @flag = @@ERROR
  
  很显然通过flag output参数可以得到User的创建操作最终执行的结果:-1代表重名,0代表成功,大于0代表出现不可预知的异常。
  
  说实话,我不太喜欢这样的异常处理方式,其实这并不是说这样的处理不好,大部分还是由于个人喜好决定。我觉得,既然添加一个同名的User本身代表一种Exception,从语义上讲,认为地抛出这样Exception的方式好像更加合理一点,所以我们喜欢通过调用RAISEERROR的方式将一个Error抛出。
  
  二、 RAISEERROR
  RAISEEROR是一个系统函数,用于奖某个可以预知的Exception抛出,供Application捕捉并处理,下面是RAISERROR的声明:
  
  RAISERROR ( { msg_id | msg_str | @local_variable }
   { ,severity ,state }
   [ ,argument [ ,n ] ] )
  [ WITH option [ ,n ] ]
  
  
  msg_id | msg_str | @local_variable:代表被你抛出的Error的Message,你可以同国3中方式来表示Message:msg_id带面sys.messages中的message_id, msg_str表示一个自定义的文本,@local_variable则表示message的变量。
  
  Severity:一个代表严重程度的数字,其范围为0-25,其中0-18可以由任何用户指定,19-25只能由sysadmin指定。一般地,0-10为严重程度很低的错误,11-18来高级别的错误,19-25代表非常严重的错误,以致在执行完成之后会终止当前的Session。
  
  State:一个0-127的整数,代表一个错误状态,对于在多个地方抛出Message一致的的情况,将State在不同的地方设置在不同的值,在Debug的时候可以很快知道是哪里出错了,所以State具有很现实的意义。
  
  Argument:向我们调用String.Format(string,…)一样,我们可以在一个一个参数中使用{0:G}{1:D}这样的站位符和进行格式处理的字符,这些站位符由后面的参数来填充。在这里也一样,在message中你一可以添加站位符,这着站位符由Argument来填充,具体如何定义,可以参阅SQL Server 2005 Books Online.
  
  WITH option [ ,...n ]:代表一些额外的选项, LOG表示进行日志记录,NOWAIT表示立即将Message递交到客户端,SETERROR强制将当前真实的@@ERROR或者message_id返回到客户端。
  
  明白了RAISERROR如何使用了后,我们可以修改我们的先前创建User的Stored Procedure:
  
  
  
  CREATE Procedure P_USERS_I
   (
   @user_id varchar(50),
   @user_name nvarchar(256)
   )
  AS
  
  IF(EXISTS(SELECT * FROM dbo.T_USERS WHERE LOWERED_USER_NAME = LOWER(@user_name) OR [USER_ID] = @user_id))
   BEGIN
   RAISERROR ('This role is already existent',16,1)
   END
  
  INSERT INTO dbo.T_USERS
   ([USER_ID]
   ,[USER_NAME]
   ,LOWERED_USER_NAME)
  VALUES(@user_id, @user_name, LOWER(@user_name)) 
    

     三、 TRY CATCH & Return
  在上面一节中,我通过RAISERROR重写了创建User的Stored procedure,实际上上面的Stored procedure是有问题的。我之所以没有立即指出,是因为这是一个很容易犯的错误,尤其是习惯了.NET Exception Handling的人更容易犯这样的错误。我们知道在.NET Application中,如果出现一个未处理的Exception,程序将立即终止,后续的程序将不会执行,但是对于上面的SQL则不一样,虽然我们通过RAISERROR将Error抛出,但是SQL的指定并不会被终止,INSERT语句仍然会被执行的。我想很多人会说在RAISERROR后加一个Return就可以了嘛。不错这是一个常用的解决方案,但是我不倾向于使用这种方法。为了更清楚地说明这个问题,我们举另一个相关的例子,上面我们介绍了创建User的例子,我们现在来引入另一个例子:如何将一个User添加到一个Role里面。由于这个例子在后面还将使用,我先讲设计的Table的结构介绍一下:T_USERS和T_ROLES分别存放User和Role,User和Role不区分大小写并且唯一,两者通过T_USERS_IN_ROLES进行关联。
  
  现在我们来写将user添加到Role的Stored Procedure:首先验证User和Role是否存在,然后验证该User和Role是否已经存在,最后将Mapping关系添加到T_USERS_IN_ROLES中:
  
  CREATE Procedure P_USERS_IN_ROLES_I
   (
   @user_name NVARCHAR(256),
   @role_name NVARCHAR(256)
   )
  AS
  DECLARE @user_id VARCHAR(50)
  DECLARE @role_id VARCHAR(50)
  SELECT @user_id = [USER_ID] FROM dbo.T_USERS WHERE LOWERED_USER_NAME = LOWER(@user_name)
  IF(@user_id IS NULL)
   BEGIN
   RAISERROR ('The user dose not exist',16,1)
   RETURN
   END
  
  SELECT @role_id = [ROLE_ID] FROM dbo.T_ROLES WHERE LOWERED_ROLE_NAME = LOWER(@role_name)
  IF(@role_id IS NULL)
   BEGIN

(编辑:IT资讯之家 www.it55.com

上一篇:实时监控网站运行情况的三种方法   下一篇:没有了

网友评论

[以下评论为网友观点,不代表本站。请自觉遵守互联网相关政策法规,所有连带责任均有评论者自负。]
[不超过250字]