SQL Server的Exception Handling

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


   RAISERROR ('The role dose not exist',16,1)
   RETURN
   END
  IF(EXISTS(SELECT * FROM T_USERS_IN_ROLES WHERE [USER_ID] = @user_id AND ROLE_ID = @role_id))
   BEGIN
   RAISERROR ('The user is already in the role',16,1)
   RETURN
   END
  INSERT INTO dbo.T_USERS_IN_ROLES([USER_ID],ROLE_ID) VALUES(@user_id,@role_id)
  
  
  虽然说在上面的Stored procedure中,我们在困难出现Exception的地方添加了RETURN,从而防止了后续的程序继续执行,但是对于一些我们无法预知的Exception呢?我们该如何添加这个RETURN呢?我想有人会说在每条语句执行之后都通过@@ERROR判断是否有Exception出现,我知道很多人喜欢这么做,而事实上,我现在真在维护的一些Stored procedure就是这么做的:全篇都是IF@@ERROR RETURN。其实我们完全可以通过其它的方式是我们的SQL看出来更加优雅一点。那就是使用我们很熟悉的TRY CATCH。在SQL Server中我们通过BEGIN TRY/END TRY和BEGIN CATCH/END CATCH这样的结构来进行Exception Handling。
  
  通过TRY CATCH,上面的Stored procedure可以改成下面的样子:
  
  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)
  
  DECLARE @error_message NVARCHAR(256)
  DECLARE @error_serverity INT
  DECLARE @error_state INT
  
  BEGIN TRY
  
  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)
   END
  
  SELECT @role_id = [ROLE_ID] FROM dbo.T_ROLES WHERE LOWERED_ROLE_NAME = LOWER(@role_name)
  IF(@role_id IS NULL)
   BEGIN
   RAISERROR ('The role dose not exist',16,1)
   END
  IF(EXISTS(SELECT * FROM T_USERS_IN_ROLES WHERE [USER_ID] = @user_id AND ROLE_ID = @role_id))
   BEGIN
   RAISERROR ('The user is already in the role',16,1)
   END
  INSERT INTO dbo.T_USERS_IN_ROLES([USER_ID],ROLE_ID) VALUES(@user_id,@role_id)
  
  END TRY
  
  BEGIN CATCH
  
   SET @error_ message = ERROR_MESSAGE)
   SET @error_serverity = ERROR_SEVERITY()
   SET @error_state = ERROR_STATE()
   RAISERROR(@error_message,@error_serverity,@error_state)
  
  END CATCh
  
  当执行上面一个SQL的时候,碰到任何一个我们自己抛出的Exception和系统异常,都会跳到Catch Block中执行相应的操作。在CATCH中,我们把在TRY Block中遇到的Error从新抛出。
  
  在这里有一些需要注意的是:并非所有的Error都会使用SQL的执行流入Catch Block,下面是两个主要的例外:
  
  Severity<10
  Severity>20并且会马上中止Session
  此外,相信大家也看见了在Catch中使用了一些Error作为前缀的Function,这些Function为系统定义的Function,用于返回当前Error的一些信息,这样的Function有:
  
   ERROR_NUMBER():返回Error Number,相当于@@ERROR。
   ERROR_MESSAGE():返回Error message.
   ERROR_SEVERITY():返回Error严重级别.
   ERROR_STATE() :返回Error的状态.
   ERROR_LINE() :返回出现Error的行号.
   ERROR_PROCEDURE() :返回出现Error的Stored Procedure名称.
  四、 Error message & sys.messages
  从前面的部分我们可以主要介绍了一种基于RAISERROR和TRY/CATCH的异常处理机制,个人觉得这是一种值得推荐的做法。但是上面的处理有一种不太理想的做法是:在每个Stored procedure中为不同的Error定义了Message。其实在很多情况下,每个Stored procedure都需要处理一些共同的Error,而且对于.NET Application来说往往是通过Message来判断Exception的类型,所以保持各个Stored Procedure的Message的一致性和Stored procedure和Application的Message的一致性就显得尤为重要。所以我们希望的做法是一次定义,对此使用。在Oracle中,我们知道我们可以通过定义具有全局意义的常数来解决,而对于SQL Server,没有全局常数的概念(在我的印象中好像没有),我们需要寻求另一种解决方案:将Message 添加到sys.messages中。
  
  在前面的部分我们说过,sys.messages是可以用于专门存放Error相关的信息:Error number, severity,state,message等。而且他不但可以用于系统与定义error的存储,也可以用于存放我们自定义的Error。更加可喜的是,SQL Server定义了一些built-in stored procedure来用于message的添加、删除和修改:
  
  sp_addmessage [ @msgnum = ] msg_id , [ @severity = ] severity , [ @msgtext = ] 'msg'

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

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

网友评论

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