• SQL Server Errors Handling Overview


    以前的编程习惯一直不太好,不管是写C,C++,C#还是数据库脚本一般都是调试测试通过即可,从来不加try/catch等异常处理。现在开始为了良好的编程习惯和一个case,开始学着在有必要处理异常的时候增加异常处理代码。

    SQL Server似乎以前错误处理功能不怎么样,现在肯定有了很大改进,但我肯定是没这个资格指手画脚。。。不管好坏,学会用是第一步。

    1. 基础
    1.1 Error Message

    一般SQL Server的错误消息如下:
    Server: Msg 547, Level 16, State 1, Procedure error_demo_sp, Line 2
    UPDATE statement conflicted with COLUMN FOREIGN KEY constraint 'fk7_acc_cur'.
    The conflict occurred in database 'bos_sommar', table 'currencies', column 'curcode'.
    The statement has been terminated.

    包括以下几个部分:
    Message number:大于50000的为自定义消息,具体信息在master..sysmessages表里,可以用sp_addmessage来添加消息。
    Severity level:0-25,0-10是信息或警告,编程错误为11-16,17-25为资源错误、硬件错误或SQL Server内部错误。>=20的错误会导致连接终止。
    State:0-127,但是是undocumented。。。特例是对于OSQL和ISQL,如果State为127,会停止并将ERRORLEVEL设置为message number,用来处理安装脚本时的错误
    Line:如果为0说明是procedure调用时出错。

    客户端决定呈现的格式。

    数据库引擎的错误处理分两个层面:T-SQL层面和应用程序代码层面。

    1.2 T-SQL
    1.2.1 TRY...CATCH
    T-SQL中的TRY/CATCH用法和C++或C#中差不多,不过看上去没有Finally。。。
    注意点1:在CATCH块处理完错误之后,会跳到END CATCH后的第一句。如果END CATCH已经是存储过程或触发器的最后一句了,那么就返回调用存储过程或触发器的那一句。在TRY块中所有出错之后的代码被忽视。
    注意点2:severity(严重度)>=20,导致数据库引擎关闭连接的,不能被处理
    注意点3:severity(严重度)<=10,视为警告或信息消息,,不能被处理
    注意点4:要捕捉编译阶段或重编译阶段的错误,使用sp_executesql

    1.2.2 ERROR 函数
    T—SQL中要获得异常信息,先要加TRY...CATCH结构,然后在结构内使用ERROR_LINE, ERROR_MESSAGE, ERROR_NUMBER, ERROR_PROCEDURE, ERROR_SEVERITY 和 ERROR_STATE。看函数名就知道是派什么用的了。注意点1:如果在TRY...CATCH结构外使用就会返回NULL。(某个case中customer问为什么会返回NULL,估计就是这个原因。。。)
    注意点2:CATCH块内不管被引用几次,不管在哪里引用,返回信息都一样。
    注意点3:对于嵌套CATCH块,哪层的异常处理返回哪层的信息。

    1.2.3 @@ERROR
    捕捉之前运行的T-SQL语句的错误号,除了某个特例一般默认为0,对于11以上的message自增。对于SQL Server 2005之前的版本,如果要获得详细错误信息有些麻烦,但如果拥有sysadmin权限的话还是可能实现的(DBCC OUTPUTBUFFER)。一般不可能阻止SQL Server报错。
    其中比较重要的11-16错误号代表的信息:
    11 – Specified Database Object Not Found
    12 – Unused
    13 – User Transaction Syntax Error
    14 – Insufficient Permission
    15 – Syntax Error in SQL Statements
    16 – Miscellaneous User Error

    注意点1:@@ERROR与运行之后发生的错误没关系。
    注意点2:如果是TRY块出错,@@ERROR要为CATCH的第一句;如果不是TRY块出错,@@ERROR要紧跟着出错的那一句。
    注意点3:@@ERROR必须被保存到临时变量中才能对其进行操作

    错误:

    Code

    正确:

    Code


    注意点4:另外相关的变量:@@rowcount(错误影响的行),@@trancount(事务数量)

    1.2.4 Uncommittable Transactions(不可提交的事务)
    TRY...CATCH中事务可能会打开但无法提交。当使用DDL或SET XACT_ABORT 设置为 ON 时都会进入该状态。
    这里涉及到了用XACT_STATE 函数在CATCH块中测试事务状态。XACT_STATE有三种返回值:1为有正常活动事务,0为没有活动的用户事务,-1为有活动事务,但存在错误无法提交,需要被ROLLBACK TRANSACTION回滚。

    1.2.5 Stored Procedure返回值
    如果没有发生错误,那么返回值为0;如果发生错误,可能返回-1或0。

    1.2.6 SET XACT_ABORT
    SET XACT_ABORT OFF对应Statement-termination
    SET XACT_ABORT ON对应Batch-abortion
    XACT_ABORT应该是execution action aborted的缩写。

    1.3 Handling Errors and Messages in Applications
    针对ODBC,ADO,ADO.NET,SqlClient,OleDb处理方法也不同。

    2. 异常发生的背后
    针对不同错误SQL Server可能的应对方法也不一样。

    可能采取的行动:
    1. 语句终止(Statement-termination)。对于open transaction需要手动ROLLBACK TRANSACTION,不然之后的INSERT/UPDATE/DELETE不会自动回滚。
    2. 范围中止(Scope-abortion)。A,B都为stored procedure,A调用B,B发生错误中止但A调用B之后的代码照常执行。通常限于编译错误。
    3. Batch中止(Batch-abortion)。客户端提交到SQL Server的整个一批都中止,所有open transaction回滚。
    4. 连接终止(Connection-termination)。open transaction回滚。@@ERROR不能获取值。通常是严重服务器端错误,除了一个例外:sp_OAxxxxx调用自定义stored procedure或OLE objects(应该是和DMO有关)。RAISERROR>=20的话也可以做到。

    判断是语句终止还是batch中止有些困难,具体情况具体分析。

    以下的两种情况不会(但没有官方说明)发生:
    1. 事务回滚,但当前batch继续执行
    2. batch中止,但事务不回滚。

    有一种需要注意的是客户端的批取消(batch-cancellation)。客户端可以随时要求SQL Server中止执行batch,SQL Server可能会立即响应,也可能会延迟一会响应,且不会回滚事务(INSERT/UPDATE/DELETE/Trigger中会回滚)。更常见的场景是客户端timeout。ODBC, OLE DB, ADO 和 ADO.Net 都有30秒的默认timeout设置。可以通过设置 .CommandTimeout来避免这个问题。

    SQL Server如何决定采取什么行动?除了特例SET XACT_ABORT OFF(这就是某位客户的关键问题所在,自从SQL Server 2005中说在触发器中这个特性取消了,明明还可以起作用的说。。。)和Trigger Context(那个客户的问题偏偏还是触发器中的SET XACT_ABORT OFF。。。)

    对于Trigger Context,所有的错误都会终止batch并从这个节点开始回滚(例外是RAISERROR和error 266)。另外如果@@trancount为0(对于Trigger Context至少为1)时也会终止。所以Trigger内错误处理的模板应该为:

    Code

     


    参考内容:
    SQL Server BOL - Handling Database Engine Errors
    http://www.sommarskog.se/error-handling-I.html
    http://www.sommarskog.se/error-handling-II.html
    http://rusanu.com/2007/10/31/error-handling-in-service-broker-procedures/
    http://www.windows-tech.info/15/397cd9af617c7a4e.php

  • 相关阅读:
    51nod1278 相离的圆
    CodeForces
    SPOJ
    51nod 1040(欧拉函数)
    51nod1009 51nod1042(数位dp)
    51nod1264 线段相交
    51nod1050 循环数组最大子段和
    Spark SQL UDF示例
    Spark SQL官网阅读笔记
    Spark RDD
  • 原文地址:https://www.cnblogs.com/galaxyyao/p/1389081.html
Copyright © 2020-2023  润新知