1. 错误可能发生执行的各个阶段,包括语法检查阶段、对象名称识别阶段、语句执行阶段;错误即可以在数据库引擎中处理,也可以在应用程序中处理
  2. 错误类型,根据错误发生时机区分:
  • Syntax Errors,语法错误
  • Object Resolution Errors,对象识别错误
  • Statement Terminating Errors,语句终止错误,发生错误的下一条语句继续执行
  • BatchConnectionServer Terminating Errors,通常都是非常严重的错误,比如硬件错误,非常少见
  1. 错误本身也是一个对象,具有如下属性:
  • Error number:唯一的错误编码
  • Error Message:错误信息,经过了本地化,使用sys.messages视图查看信息时,为每个message_id(即Error number)返回对个message,每个message对应不同的language_id,即对应不同语言
  • Severity,严重性
  • State,决定发生错误的代码的位置,是在代码中中由开发者定义的,在raise error中可以指定一个state
  • Procedure Name,存储过程或者触发器的名称,如果有的话
  • Line Number,表明发生错误的代码行
  1. 错误严重性:
  • 0-9,信息
  • 10,返回状态的信息
  • 11-16,需要用户纠正的错误,比如11表示对象不存在,13表示事务死锁,14表示像没有权限这样的错误,15表示语法错误
  • 17-19,用户无法纠正的软件错误,比如17表示资源用尽(比如内存、磁盘空间、锁等资源)
  • 20-24,严重的系统错误
  • 25SQL Server服务终端错误
  1. RAISE ERRORPRINT都可以返回信息或者错误,PRINT相当于返回Severity10的信息;%d是数字占位符,%s是字符串占位符;有两种方式,一种是使用sp_addmessage创建用户自定义的错误信息,一种是指定错误字符串,此时error number总是5000
  2. @@ERROR是一个系统变量,保存上次发生错误的error number,如果语句成功执行返回0,否则返回error number,每个语句执行完都要修改该值,因为只要错误一出现就要尽快捕获该值
  3. 大部分错误是语句终止错误,即只有发生错误的语句回滚,然后继续执行下一条语句;当设置SET XACT_ABORT ON语句时,语句终止错误应该变为批处理终止错误,即语句发生错误时,整个批处理进行回滚,而不仅仅是单个语句回滚
  4. SQL Server不支持自治事务autonomous transactions,自治事务就是不在同一个范围内的嵌套事务,其提交和回滚不影响外部事务;@@TRANCOUNT系统变量返回事务嵌套层级,存储过程要求在开始和退出时@@TRANCOUNT必须是一致的,否则抛出错误286,通常用来防止嵌套事务
  5. sp_addmessage允许添加自定义的错误信息,指定的error number必须是50000或者以上,可以指定语言(@lang参数),@with_log设置为true时,返回错误时会将错误记录到Windows Application log@replace用于替换已有的自定义消息的Message,使用该系统存储过程时,必须具有sysadmin或者serveradmin权限;注意不能引发系统错误
  6.  BEGIN CATCH语句必须跟在END TRY之后;在T-SQL中没有等价于FINALLY的语句,没有rethrowing机制,只有大于50000的错误可以手工抛出,即不能在CATCH语句中引发一个系统错误
  7. CATCH语句块为捕获错误信息提供了比@@ERROR更丰富的选择,可以在CATCH语句块中执行错误处理函数,返回错误信息,错误处理函数还可以定义成存储过程以便重用,这些错误处理函数在整个CATCH语句块中始终都保持同一个值,不存在像@@ERROR值被轻易修改的问题
  8. 不是所有的错误都可以在当前范围的TRY/CATCH语句块中捕获,通常来说,在当前范围不能捕获的错误,可以在包含他们的范围内捕获,比如不能在存储过程内部TRY/CATCH语句块中捕获的错误,可以在调用存储过程的TRY/CATCH语句块中捕获;通常不能捕获的错误包括:编译错误、语句级别重新编译问题(通常是名称识别错误)
  9. CATCH语句块不会自动回滚异常,需要在CATCH语句块中手动回滚异常
  10. 通常来说尽量在托管代码中捕获异常,所有托管代码中未捕获的异常,传递到T-SQL代码中都是一个6522的错误,错误信息可以嵌套,SQL CLR Messages需要解包去找到内部错误,而不是封装的6522错误,托管代码中也可以执行RAISERROR语句