c++ try catch语句_数据库大师成长日记:一文玩通使用try...catch捕捉sql异常

我们在写SQL脚本时,特别是针对封装的存储过程,很难保证脚本在执行过程中不会出现异常和错误。一个优秀负责的程序员,会花费足够的时间、预先在脚本中设置异常捕捉和处理语句,以方便脚本的调试和与客户端消息互通。

bed116dca45662a906f9919db46f905c.png

在PostgreSQL中,可以使用raise抛出异常、使用begin ... exception ... when ... then ... end的方式捕捉异常,MySQL则使用declare ... handler定义异常。SQL Server的异常处理以2008为分水岭,之前的方式非常繁琐、之后的方式则非常清爽。

今天我们就以SQL Server为例,详细说明下如何在SQL脚本中捕捉错误。

MSSQL2000的错误捕捉

在SQLServer2000中,捕捉异常是非常繁琐的。要通过@@ERROR跟踪SQL执行的情况,如果SQL执行正常,@@ERROR值是0,如果出现错误,@@ERROR返回对应的错误号,错误处理就是根据@@ERROR的值进行处理的。

笔者之前在SQLServer2000环境写的存储过程中,每执行一句SQL,就要跟着写一句错误判断,非常繁琐。抓个当年写的片段了解下:

c0d89d6bea605ae7c5585fac13e2c2ec.png

在执行完一条SQL语句之后,马上判断@@error的值,如果@@error<>0,则设置错误提示内容,并使用goto语句跳转到错误处理部分。

MSSQL2008及以后的错误捕捉

可喜的是,从2008开始,SQLServer开始支持使用try...catch方式捕捉和处理SQL异常。不要小看这个变化,这可是质变,从此我们就摆脱了对异常繁琐的跟踪。

我们可以将大段的SQL脚本用try语句包裹起来,在try后面跟着catch语句,当sql执行出现错误时,会自动跳转到catch段落进行错误处理。我们先来看看try...catch的语法格式:

BEGIN TRY  SQL段落END TRY BEGIN CATCH  处理段落END CATCH;
3961de35d9eaf1e93c3671336462a0c3.png

语法格式可能与我们想象的有点不一样,搞编程的朋友都知道,比如在Delphi中,使用的try...except...end和try...finally...end捕捉和处理异常;Java和C#的方式最优雅,使用try...catch...finally捕捉和处理异常。MSSQL的try...catch虽然比不过Java和C#的清爽,但比起每执行依据都要判断的方式,不知道要好了多少倍呢。

MSSQL抛出异常之后,提供了一系列的异常函数获取异常的说明,主要包括以下几个内置函数:

  • ERROR_NUMBER() 返回错误编号。
  • ERROR_SEVERITY() 返回严重性。
  • ERROR_STATE() 返回错误状态号。
  • ERROR_PROCEDURE() 返回出现错误的存储过程或触发器的名称。
  • ERROR_LINE() 返回导致错误的脚本中的行号。
  • ERROR_MESSAGE() 返回错误消息的完整文本。
93ead50e38512ab610e799305dcac734.png

结合这些内置错误说明的函数,我们就可以在catch段落进行相应处理了。下面我们举一个捕捉异常的例子:

begin try declare @x int=1,@y int=0; set @x=@x/@y;end trybegin catch select  error_number() as 错误编号, error_severity() as 严重性, error_state() as 错误状态号, error_procedure() as 存储过程, error_line() as 错误行号, error_message() as 错误信息;end catch;

这是一个明显的被零除错误,运行效果参看下图:

6f2fd26590dea69a8e764483cefceb3e.png

脚本中第3行,出现了被零除的错误,在catch段的异常捕捉部分,我们返回了错误的说明。在系统表sys.messages中,存放着所有系统错误的说明,“8134”则对应表中的message_id字段,对应的错误描述如下图所示:

8ed47d852645317f0dfa6572596d1ba9.png

MSSQL每一种内置错误,针对每种支持的语言,都有对应的错误描述,这里我们就不展开说明了。

使用THROW主动抛出异常

很多时候,我们并不是非要等着SQL语句执行错误才返回异常,而是根据业务需要返回提示错误。比如用户输入的用户名密码不匹配,我们抛出异常,告知客户端用户名或密码错,这就要使用throw语句来抛出异常了。

throw的语法格式如下:

THROW 错误编号, 错误信息, 错误状态
  • 错误编号:表示异常的常量或变量,类型int,要求大于等于50000且小于等于2147483647,以避开内置错误消息内码。
  • 错误信息:描述异常的字符串或变量。message类型为nvarchar(2048)。
  • 错误状态:0到 255之间的常量或变量,指示与消息关联的状态。

这里的错误编号,进入catch块后,使用error_numer()进行捕捉,错误信息使用error_message()捕捉,错误状态使用error_state()捕捉,Throw的严重性代码永远都是16。

参看下面的示例脚本:

begin try declare @username nvarchar(100)='张三'; declare @password varchar(255)='12345'; if not (@username='张三' and @password='123456') throw 50000,'用户名或密码错误!',1;end trybegin catch select error_number() as 错误编号, error_severity() as 严重性, error_state() as 错误状态号, error_procedure() as 存储过程, error_line() as 错误行号, error_message() as 错误信息;end catch;

下图是运行效果:

edf7b30eb5eecb18884faf87b2234615.png

这是人为抛出的异常,与SQL语句执行的异常是不同的,但都会跳转到catch段落统一处理。

一般在存储过程中,我们在try开始前执行begin tran,语句块最后执行commit tran,在catch模块执行rollback tran,从而实现事务的控制。这里就不再赘述了。

如果我们能活用throw触发异常、使用try ... cath ...捕捉和处理异常,我们的脚本就显得更加健壮安全。这对一个优秀的数据库程序员显得非常重要。您说呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值