谈谈基于sqlserver的exceptionhandling

上传人:自*** 文档编号:80757082 上传时间:2019-02-20 格式:DOCX 页数:29 大小:317.05KB
返回 下载 相关 举报
谈谈基于sqlserver的exceptionhandling_第1页
第1页 / 共29页
谈谈基于sqlserver的exceptionhandling_第2页
第2页 / 共29页
谈谈基于sqlserver的exceptionhandling_第3页
第3页 / 共29页
谈谈基于sqlserver的exceptionhandling_第4页
第4页 / 共29页
谈谈基于sqlserver的exceptionhandling_第5页
第5页 / 共29页
点击查看更多>>
资源描述

《谈谈基于sqlserver的exceptionhandling》由会员分享,可在线阅读,更多相关《谈谈基于sqlserver的exceptionhandling(29页珍藏版)》请在金锄头文库上搜索。

1、对于所有的开发人员来说,Exception Handling是我们每天都要面对的事情。对于基于Source Code的Exception Handling,我想大家已经司空见惯了,但是对于Database级别的Exception Handling,就没有那么常见了。在这篇文章中,我将会介绍我对于基于Database编程中Exception Handling的一些粗浅的认识:在编写Stored Procedure时,如何抛出一个可预知的Exception,ADO.NET如何处理从Database抛出的Exception,如何保存基于Database Exception的Error Message

2、,如何在Database和.NET Application之间进行消息的传递注:这里的Database主要指SQL Server。ERRORRAISEERRORTRY CATCH & ReturnError message & sys.messagesADO.NET Exception HandlingSqlExceptionInfoMessage一、 ERRORERROR是我们经常使用的系统函数,其返回类型为INT,用以表示上一个语句的执行是否遇到错误,0便是语句正常执行,非0则以为着某个错误的产生。比如下面的一个例子:我在SQL Server Management Studio中执行下面一

3、段简单的SQL:DECLARE result INTSET result = 10/0PRINT ERRORGo会得到如下的执行结果:由于除零导致错误的产生,使ERROR的值变成8134。实际上8134是一个Error Number,代表某个系统定义的Error,每个预定义的Error由一个唯一的Error Number来唯一标识。ERROR本质上就是返回上一个语句执行遇到的Error的ID号,所以这并不是一个随机的值,无论是10/0还是100/0,ERROR返回的结果都是一样的。由于可以通过ERROR得到Error的类型,可以帮助我们在编写Stored Procedure的过程中,借助这个E

4、RROR进行一些流程的控制。比如我们知道Error Number为547代表违反外键约束,我们就可以通过ERROR的结果是否等于547来进行异常的处理:UPDATE T_USERS_IN_ROLES SET USER_ID = dummy textIF ERROR = 547PRINT The user is not existent通过我们上面一个截图我们发现,在SQL Server Management Studio中执行任何一个语句的时候,如果遇到一个预定义的Error,会打印出相关的Error Message。这些Error Message到底是如何存储的呢?Error message

5、和Error Numbder又是如何进行关联的呢?实际上,SQL Server通过一个名为sys.messages的系统表来存储关于Error的一些信息关于sys.messages,在后续的章节中还会提及。下面是sys.messages的结构:message_id不仅仅代表message的唯一标识,对于一个预定义的Error,其Error number就是这个message_id。由于Localization的需要,我们需要为不同的语言定义不同的Message,这些Message共享一个message_id, 具体采用何种语言通过luange_id来标识。Severity代表Error的严重程

6、度,我将在后续部分专门介绍。is_event_logged是一个Indicator,表明出现该Error是否需要在Event log中进行日志记录,text当然就是message文本了。我们可以通过下面的SQL来进行验证:DECLARE result INTDECLARE error INTSET result = 5/0SET error = ERRORSELECT error,sys.messages.* FROM sys.messages WHERE message_id = errorGo下面是执行的结果:对于ERROR,有一点需要特别提醒的是:它仅仅代表前一个语句执行的Error N

7、umber,之后任何一段语句的执行都会改变ERROR的值,甚至是一个IF语句。我想通过下面一段SQL,你肯定会后一个深刻的认识:我们可以看到,一个简简单单的IF语句就将ERROR从8134变成了0。不过想想也很简单,IF语句本身也是一个执行语句,在执行过程中并没有遇到Error,所以ERROR应该返回0。这也是我在上面的Sample中通过SET error = ERROR将ERROR进行预存的原因。ERROR实际上代表的是在编写SQL或者Stored procedure中对异常的识别,大多数我们通过ERROR来判断一段SQL语句是否成功执行,保证没有遇到不可预知的异常。对于一些可以预知的异常在

8、SQL中又该如何处理呢?我发现很多程序员喜欢使用Output参数来处理这些预知的异常。比如:我们需要编写一个添加User的Stored procedure,user name具有唯一性,添加一个和database中同名的user显然是不合法的,在很多情况下通过一个Output参数来返回操作最终执行的情况,比如:CREATE Procedure P_USERS_I(user_id varchar(50),user_name nvarchar(256),flag INT OUTPUT)ASIF(EXISTS(SELECT * FROM dbo.T_USERS WHERE LOWERED_USER_

9、NAME = LOWER(user_name) OR USER_ID = user_id)BEGINSET flag = -1RETURNEND 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代表出现不可预知的异常。说实话,我不太喜欢这样的异常处理方式,其实这并不是说这样的处理不好,大部分还是由

10、于个人喜好决定。我觉得,既然添加一个同名的User本身代表一种Exception,从语义上讲,认为地抛出这样Exception的方式好像更加合理一点,所以我们喜欢通过调用RAISEERROR的方式将一个Error抛出。二、 RAISEERRORRAISEEROR是一个系统函数,用于奖某个可以预知的Exception抛出,供Application捕捉并处理,下面是RAISERROR的声明:RAISERROR ( msg_id | msg_str | local_variable ,severity ,state ,argument ,n ) WITH option ,n msg_id | msg

11、_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的整数,代表一个错

12、误状态,对于在多个地方抛出Message一致的的情况,将State在不同的地方设置在不同的值,在Debug的时候可以很快知道是哪里出错了,所以State具有很现实的意义。Argument:向我们调用String.Format(string,)一样,我们可以在一个一个参数中使用0:G1:D这样的站位符和进行格式处理的字符,这些站位符由后面的参数来填充。在这里也一样,在message中你一可以添加站位符,这着站位符由Argument来填充,具体如何定义,可以参阅SQL Server 2005 Books Online.WITH option ,.n :代表一些额外的选项, LOG表示进行日志记录,

13、NOWAIT表示立即将Message递交到客户端,SETERROR强制将当前真实的ERROR或者message_id返回到客户端。明白了RAISERROR如何使用了后,我们可以修改我们的先前创建User的Stored Procedure:CREATE Procedure P_USERS_I(user_id varchar(50),user_name nvarchar(256)ASIF(EXISTS(SELECT * FROM dbo.T_USERS WHERE LOWERED_USER_NAME = LOWER(user_name) OR USER_ID = user_id)BEGINRAIS

14、ERROR (This role is already existent,16,1)ENDINSERT 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的

15、人更容易犯这样的错误。我们知道在.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是否已经存在,最后将Map

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号