sql server锁异常_SQL Server中异常处理的背景

sql server锁异常

RAISERROR statement. RAISERROR语句。 Figure 1 demonstrates a combination of mandatory parameters (i.e. 图1展示了为成功使用RAISERROR函数而应提供的必需参数(即 msg_id/msg_str, severity, state) as well as optional parameters (i.e. msg_id / msg_str,severity,state )和可选参数(即 WITH option) that ought to be provided for the purposes of successfully using the RAISERROR function. WITH选项 )的组合。

Figure 1

Figure showing a combination of parameters for successful usage of RAISERROR function

图1

The content of an exception message raised through the RAISERROR statement can either be hard-coded or retrieved from the sys.messages catalog view based on a corresponding error code number:

通过RAISERROR语句引发的异常消息的内容可以是硬编码的,也可以基于相应的错误代码号sys.messages 目录视图检索

  1. An example of declaring and raising a user-defined error message within a RAISERROR statement is illustrated in Figure 2. In this example, a SQL Server stored procedure is created under the sample AdventureWorks2012 database that, amongst other things, uses a local variable (@StringVariable) in order to declare and set a custom message to handle an exception of dividing by zero.

    图2中显示了一个在RAISERROR语句中声明和引发用户定义的错误消息的示例在此示例中,在示例AdventureWorks2012数据库下创建了一个SQL Server存储过程 ,该数据库除其他外还使用局部变量( @ StringVariable ),以便声明并设置自定义消息以处理除以零的异常。

    Figure 2

    Figure illustrating an example of a stored procedure

    图2

    Now, for the purposes of simulating an application calling the stored procedure created in Figure 2, Figure 3 shows a SQL Server 2012 Integration Services (SSIS) Package that uses an SSIS’s Execute SQL Task (EST) – titled RAISERROR Customer Error Messages – to execute a stored procedure that was created in Figure 2.

    现在,为了模拟调用图2中创建的存储过程的应用程序, 图3显示了一个SQL Server 2012 Integration Services (SSIS) 程序包 ,该程序包使用SSIS的Execute SQL Task (EST)(标题为RAISERROR Customer Error Messages)来执行图2中创建的存储过程。

    Figure 3

    Figure showing a SQL Server 2012 Integration Services Package that uses an SSIS’s Execute SQL Task

    图3

    The execution of the EST leads to an error and the error message returned to SSIS is shown in Figure 4. It can be noticed that the user-defined custom error message is returned to SSIS as a calling application.

    EST的执行导致错误,并且返回到SSIS的错误消息如图4所示。 可以注意到,用户定义的自定义错误消息作为调用应用程序返回给SSIS。

    Figure 4

    Figure illustrating an error message returned to SSIS

    图4

  2. sys.messages引发

    Exceptions stored in the sys.messages can be retrieved by referencing ERROR_MESSAGE, ERROR_SEVERITY and ERROR_STATE system functions. Figure 5 demonstrates a stored procedure that set values of system functions to local variables and RAISERROR then references the locally declared variables.

    可以通过引用ERROR_MESSAGEERROR_SEVERITYERROR_STATE系统函数来检索sys.messages中存储的异常。 图5演示了一个存储过程,该过程将系统函数的值设置为局部变量,然后RAISERROR引用局部声明的变量。

    Figure 5

    Figure showing a stored procedure that set values of system functions to local variables and RAISERROR

    图5

    Similarly to an example on re-throwing user-defined exceptions, the stored procedure created in Figure 5 is referenced in an SSIS Package (as shown in Figure 6) and the result of SSIS package execution is displayed in Figure 7.

    类似于重新抛出用户定义的异常的示例,在SSIS包中引用了图5中创建的存储过程( 如图6所示),在图7中显示了SSIS包执行的结果。

    Figure 6

    Figure showing how previously created stored procedure is referenced in an SSIS Package

    图6

    Figure 7

    Figure displaying the result of SSIS package execution

    图7

使用THROW语句SQL Server 2012异常处理 (SQL Server 2012 exception handling using THROW statement)

The preceding section demonstrated the prevalent ways of handling exceptions in versions of SQL Server prior to SQL Server 2012. This section focuses on the alternative way to exception handling as of SQL Server 2012 by using the THROW statement. Figure 8 shows the syntax that should be followed in order to successfully make use of the THROW statement.

上一节演示了在SQL Server 2012之前SQL Server版本中处理异常的普遍方法。本节重点介绍使用THROW语句从SQL Server 2012开始的异常处理的替代方法。 图8显示了成功使用THROW语句应遵循的语法。

Figure 8

Figure showing the syntax that should be followed in order to successfully make use of the THROW statement

图8

Noticeably in this syntax is the disappearance of mandatory parameters that dictates the usage of RAISERROR. Thus, the THROW statement is simpler and easier to use compared to RAISERROR as you have an option of not parsing any parameters. For instance, Figure 9 shows a stored procedure that, like the example given in the RAISERROR discussion, attempts to divide by zero. However, unlike the numerous local variables that were used in the RAISERROR discussion for catching exceptions, Figure 9 simply shows that it only takes a single line within the CATCH block to handle exceptions when the THROW statement is used.

值得注意的是,此语法中指示RAISERROR用法的必需参数的消失。 因此,与RAISERROR相比,THROW语句更易于使用,因为您可以选择不解析任何参数。 例如, 图9显示了一个存储过程,类似于RAISERROR讨论中给出的示例,该存储过程试图除以零。 但是,与RAISERROR讨论中用于捕获异常的大量局部变量不同, 图9仅显示了使用THROW语句时,它仅在CATCH块内使用一行来处理异常。

Figure 9

Figure illustrating that it only takes a single line within the CATCH block to handle exceptions when the THROW statement is used

图9

Furthermore, when the stored procedure created in Figure 9 is used in an SSIS Package (as shown in Figure 10), the exception returned looks similar to the exception that was returned when RAISERROR referenced the sys.messages object (as shown in Figure 11) – except of course that it took less lines of code to achieve this using THROW than it did whilst using RAISERROR.

此外,当在SSIS包中使用图9中创建的存储过程( 如图10所示)时,返回的异常类似于RAISERROR引用sys.messages对象时返回的异常( 如图11所示)。 –当然,与使用RAISERROR相比,使用THROW花费更少的代码行来实现这一目标。

Figure 10

Figure showing using the previously created stored procedure in an SSIS package

图10

Figure 11

Figure showing that the returned exception looks similar to the exception that was returned when RAISERROR referenced the sys.messages object

图11

抛出与RAISERROR:使用不同方法警告SQL Server 2012异常处理 (THROW vs RAISERROR: Different approaches towars SQL Server 2012 exception handling)

The preceding section indicated that there is ultimately a simpler and convenient way of re-throwing exceptions when THROW statement is used as compared to RAISERROR. However, the examples demonstrated in preceding sections should not justify an absolute replacement of any T-SQL code that references RAISERROR with a THROW statement. Instead, RAISERROR can still be utilised for some of the requirements that the THROW can’t fulfil.

上一节指出,与RAISERROR相比,当使用THROW语句时,最终有一种重新抛出异常的简便方法。 但是,前几节中演示的示例不应证明用THROW语句绝对替代任何引用RAISERROR的T-SQL代码。 相反,RAISERROR仍可用于THROW无法满足的某些要求。

In this section we will take a closer look at the differences between RAISERROR versus THROW statements. Despite the two statements being used for re-throwing exceptions to calling applications, they tend to behave differently in the way they go about re-throwing exceptions. One significant difference is in the way they handle user exceptions (i.e. exceptions with error codes of 50000 or more) versus system exceptions (i.e. exceptions with error codes less than 50000). Below is a list of points that I have put together to persuade you that in some T-SQL scripts one statement maybe suitable over the other:

在本节中,我们将仔细研究RAISERROR和THROW语句之间的区别。 尽管这两个语句用于重新抛出调用应用程序的异常,但是它们在重新抛出异常的方式上往往表现出不同的行为。 他们处理用户异常(即错误代码为50000或更多的异常)与系统异常(即错误代码小于50000的异常)的方式之间的重大区别是。 下面列出了我要说服您的观点:在某些T-SQL脚本中,一条语句可能适合另一条语句:

  1. Error Line Number 错误行号进行准确的故障排除

    One of the known issues of raising an error using RAISERROR statement is often the incorrect error line number that is returned to the calling application. Noticeably, this incorrect error line number occurs when RAISERROR statement throws a user-defined exception. For instance, refer to Figure 12 whereby after the T-SQL code is executed – the error line number is given to be at 13. However, this is incorrect as the statement that causes a division by zero is actually at line number 2. This is correctly depicted in Figure 13 wherein the THROW statement is used.

    使用RAISERROR语句引发错误的已知问题之一通常是返回给调用应用程序的错误错误行号。 值得注意的是,当RAISERROR语句引发用户定义的异常时,会出现此错误的错误行号。 例如,参考图12 ,在该代码中执行T-SQL代码后-错误行号被指定为13。但是,这是不正确的,因为导致被零除的语句实际上在行号2。在图13中正确地描述了其中使用THROW语句的情况。

    Figure 12

    Figure showing that the error line number is given to be at line 13

    图12

    Figure 13

    Figure illustrating that the error line number is given to be at line 2

    图13

  2. Another discrepancy that has largely been attributed to the RAISERROR statement is the incorrect error number that is sometimes returned to calling applications. For instance, according to the sys.messages object, the message_id associated with an error incurred by dividing by zero is 8134 (as shown in Figure 14).

    很大程度上归因于RAISERROR语句的另一个差异是错误的错误号,该错误号有时会返回给调用应用程序。 例如,根据sys.messages对象,与除零引起的错误相关的message_id为8134( 如图14所示)。

    Figure 14

    The message_id associated with an error incurred by dividing by zero is 8134

    图14

    However, the error number returned after the execution of query in Figure 15 is 50000 whereas the query that uses the THROW statement, as shown in Figure 16, is returning the correct error number as 8134.

    但是,执行图15中的查询后返回的错误号为50000,而使用THROW语句的查询( 如图16所示)返回正确的错误号8134。

    Figure 15

    Figure showing that the error number is 5000 for the given query

    图15

    Figure 16

    Figure illustrating that the query which uses THROW statement is returning the correct error number as 8134

    图16

  3. There are sometimes inconsistencies in terms of whether or not T-SQL commands should be executed after RAISERROR statement is executed. Figure 17 shows that despite the exception having being raised for dividing by zero, ‘Do More’ was still printed afterwards. However, having raised an exception as a result of referencing an invalid column, ApexSQL, in Figure 18 – the statement for printing ‘Do More’ was not executed. Fortunately, such inconsistencies are not tolerated in a THROW statement as it can be seen (in both Figures 19 and 20) that commands that appear after the THROW statement are not executed at all.

    在执行RAISERROR语句后是否应该执行T-SQL命令方面有时存在不一致之处。 图17显示,尽管引发了除以零的异常,但此后仍打印'Do More'。 但是,由于在图18中引用了无效列ApexSQL而引发了异常-未执行用于打印“ Do More”的语句。 幸运的是,这样的不一致在THROW语句中是不能容忍的,因为可以看到(在图1920中 )根本没有执行在THROW语句之后出现的命令。

    Figure 17

    Figure showing that despite the exception having being raised for dividing by zero, ‘Do More’ was still printed afterwards

    图17

    Figure 18

    Figure illustrating how the statement for printing ‘Do More’ was not executed

    图18

    Figure 19

    Commands appearing after the THROW statement are not executed at all

    图19

    Figure 20

    Commands that appear after the THROW statement are not executed at all

    图20

  4. SQL Server uses exception severity levels as guide on whether it should return the exception to the client as just a warning or highly critical. Although RAISERROR dynamically returns severity level based on the nature of the exception encountered, the THROW statement invariably returns an exception with a severity level of 16. Figure 21 demonstrates a T-SQL query with conditional logic that throws an exception if the @ColorOfSky variable is not set to Blue. The severity level of this exception is given to be 16. However, the similar T-SQL code in Figures 22 and 23 shows the flexibility of RAISERROR statement in terms of setting and resetting the severity level of an error.

    SQL Server使用异常严重性级别作为有关是否应将异常作为警告或高度紧急返回给客户端的指南。 尽管RAISERROR根据遇到的异常的性质动态返回严重性级别,但是THROW语句始终返回严重性级别为16的异常。 图21演示了带有条件逻辑的T-SQL查询,如果@ColorOfSky变量为,则该查询将引发异常没有设置为Blue 。 将该异常的严重性级别设置为16。但是, 图2223中类似的T-SQL代码在设置和重置错误的严重性级别方面显示了RAISERROR语句的灵活性。

    Figure 21

    An exception is thrown if the @ColorOfSky variable is not set to Blue

    图21

    Figure 22

    Using RAISERROR to set/reset the severity level of an error

    图22

    Figure 23

    Flexibility of the RAISERROR - customizing the severity level of an error

    图23

    1. LOG

      日志
    2. NOWAIT

      等待
    3. SETERROR

      设定错误


    Figure 24 demonstrates a RAISERROR statement that makes use of the WITH LOG argument to write to Windows Application log. Figure 25 displays the application log with the exception that was raised in Figure 24.

    图24演示了RAISERROR语句,该语句利用WITH LOG参数写入Windows应用程序日志。 图25显示了应用程序日志, 图24中引发了异常。

    Figure 24

    RAISERROR statement that makes use of the WITH LOG argument to write to Windows Application log

    图24

    Figure 25

    Figure displaying the application log with the exception that was raised in the previous figure

    图25

  5. If you are used to getting away with writing T-SQL code without specifying GO or a semi-colon (;) to indicate the end of a statement – then you will find it difficult to adapt to using the THROW statement. Unless you don’t have any statement preceding the THROW statement, you will not get away with using a THROW statement without specifying T-SQL statement terminators. Furthermore, although RAISERROR permits the use of a RAISERROR statement that is preceded by a statement which does not contain T-SQL statement terminators (as shown in Figure 26), such practice is not tolerated in a THROW statement as shown in Figure 27.

    如果您习惯于不编写T-SQL代码而没有指定GO或分号(;)来指示语句的结尾,那么您将发现很难适应使用THROW语句。 除非在THROW语句之前没有任何语句,否则在不指定T-SQL语句终止符的情况下使用THROW语句将无处可逃。 此外,尽管RAISERROR允许使用在不包含T-SQL语句终止符的语句之后的RAISERROR语句( 如图26所示),但是如图27所示,THROW语句中不允许这种做法。

    Figure 26

    Using RAISERROR statement preceded by a statement not containing T-SQL statement terminators

    图26

    Figure 27

    Figure showing a THROW statement can not be preceded by a statement not containing T-SQL statement terminators

    图27

    Figures 28 and 29 demonstrates the acceptable way of using THROW statement with GO and semicolon when it is preceded by other T-SQL statements.

    图2829演示了在其他T-SQL语句之前使用THROW语句和GO和分号的可接受方法。

    Figure 28

    Using THROW statement with GO when it is preceded by other T-SQL statements

    图28

    Figure 29

    Using THROW statement with semicolon when it is preceded by other T-SQL statements

    图29

  6. All user-defined exceptions that do not exist in the sys.messages catalog view are automatically assigned an error number of 50000. However, should you want to assign an exception to any number greater than 50000, the exception would have to be inserted into the sys.messages catalog view prior to being referenced in your RAISERROR statement. Fortunately, the THROW statement does not require that an error number be registered prior to being cited. For instance, Figure 30 shows that error number (message_id) 56789 does not exist in the sys.messages catalog view. Yet, the THROW statement shown in Figure 31 is able to reference a non-existent error number whereas a similar RAISERROR statement is raising an error as shown in Figure 32.

    将自动为sys.messages目录视图中不存在的所有用户定义的异常分配一个错误号50000。但是,如果要将异常分配给大于50000的任何数字,则必须将异常插入到sys.messages目录视图,然后在您的RAISERROR语句中引用它。 幸运的是,THROW语句不需要在引用之前注册错误号。 例如, 图30显示sys.messages目录视图中不存在错误号( message_id )56789。 但是, 图31所示的THROW语句能够引用不存在的错误号,而类似的RAISERROR语句正在引发错误, 如图32所示。

    Figure 30

    Figure showing that error number 56789 does not exist in the sys.messages catalog view

    图30

    Figure 31

    THROW statement shown is able to reference a non-existent error number

    图31

    Figure 32

    RAISERROR statement is not able to reference a non-existent error number

    图32

    Following the successfully registering of the error number (message_id) 56789 in sys.messages catalog view (shown in Figure 33), RAISERROR statement is then able to re-throw an exception with this new error number (as shown in Figure 34).

    sys.messages目录视图(如图33所示)中成功注册了错误号( message_id )56789之后,RAISERROR语句随后能够使用该新错误号重新引发异常( 如图34所示)。

    Figure 33

    Successful registering of the error number 56789 in sys.messages catalog view

    图33

    Figure 34

    RAISERROR statement is able to re-throw an exception with this new error number

    图34

  7. Although you can raise both user-defined and system-defined exceptions in a RAISERROR statement, system-defined exceptions can only be raised when the THROW statement is used within a CATCH block. For instance, Figure 35 shows that RAISERROR can directly invoke system-defined error number 40645 whereas the exception returned in Figure 36 indicates that only error numbers within the range of 50000 to 2147483647 can be directly invoked in THROW statement.

    尽管可以在RAISERROR语句中引发用户定义的异常和系统定义的异常,但是仅当在CATCH块中使用THROW语句时,才可以引发系统定义的异常。 例如,图35显示RAISERROR可以直接调用系统定义的错误号40645,而图36中返回的异常表示只能在THROW语句中直接调用50000到2147483647范围内的错误号。

    Figure 35

    Figure showing that RAISERROR can directly invoke system-defined error number 40645

    图35

    Figure 36

    Only error numbers within the range of 50000 to 2147483647 can be directly invoked in THROW statement

    图36

    However, error number 8134 is a system exception but notice that (in Figure 37) it can be successfully re-thrown by the THROW statement when the statement is correctly referenced within a CATCH block.

    但是,错误号8134是系统异常,但请注意(在图37中 )当在CATCH块中正确引用该语句时,可以通过THROW语句成功将其重新抛出。

    Figure 37

    Error number 8134 is a system exception but it can be successfully re-thrown by the THROW statement

    图37

  8. The error message retrieved from the sys.messages catalog view can be customised by setting message parameter values. In order to for that to happen, part of the error message should contain the printf function. For instance, let’s add a new message in the sys.message object as shown in Figure 38:

    通过设置消息参数值,可以自定义从sys.messages目录视图检索的错误消息。 为了做到这一点,错误消息的一部分应包含printf函数。 例如,让我们在sys.message对象中添加一条新消息, 如图38所示:

    Figure 38

    Adding a new message in the sys.message object

    图38

    Now going back to our example of checking for the colour of the sky, Figure 39 demonstrates how RAISERROR statement re-throws a customised message that was added in Figure 38.

    现在回到检查天空颜色的示例, 图39展示了RAISERROR语句如何重新抛出在图38中添加的自定义消息。

    Figure 39

    RAISERROR statement re-throws a customised message

    图39

    However, substitution parameters in the message parameter are not allowed in a THROW statement. Luckily, adjustments can be made for the purposes of getting the same code to function within a THROW statement. Such adjustments include the usage of the FORMATMESSAGE function. Figure 40 demonstrates how the work around to using substitution parameters can be applied in a THROW statement.

    但是,THROW语句中不允许message参数中的替换参数。 幸运的是,可以进行调整以使同一代码在THROW语句中起作用。 此类调整包括FORMATMESSAGE函数的使用。 图40演示了如何在THROW语句中应用替代参数的解决方法。

    Figure 40

    Figure demonstrating how the workaround to using substitution parameters can be applied in a THROW statement

    图40

结论 (Conclusion)

The concept and practice of exception handling in SQL Server is not novel instead statements such as RAISERROR and the TRY/CATCH block has been influential in re-throwing exceptions back to calling applications such as SQL Server Integration Services. The introduction of the THROW statement in SQL Server 2012 has largely made the practice of raising exceptions much more convenient and simple: what used to take a combination of local variables and system functions to successfully re-throw an exception in RAISERROR statement is now easily achievable with a single line when the THROW statement is used. Yet, the THROW statement has various limitations that can only be mitigated by still applying the RAISERROR statement.

SQL Server中异常处理的概念和实践并不是新颖的,相反,诸如RAISERROR之类的语句和TRY / CATCH块在将异常重新引发回调用应用程序(如SQL Server Integration Services)方面具有影响力。 SQL Server 2012中THROW语句的引入已大大简化了引发异常的做法:使用局部变量和系统函数的组合成功在RAISERROR语句中成功抛出异常的操作现在可以轻松实现使用THROW语句时用单行表示。 但是,THROW语句具有各种限制,这些限制只能通过仍然应用RAISERROR语句来缓解。

翻译自: https://www.sqlshack.com/background-exception-handling-sql-server/

sql server锁异常

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值