为什么我们需要 SQL Server 中的异常处理?

让我们通过一个示例来了解 SQL Server 中异常处理的必要性。因此,创建一个 SQL Server 存储过程,通过执行以下查询来除以两个数字。

IF OBJECT_ID('spDivideTwoNumber','P') IS NOT NULL
DROP PROCEDURE spDivideTwoNumber
GO
CREATE PROCEDURE spDivideTwoNumber(
@Number1 INT,
@Number2 INT
)
AS
BEGIN
DECLARE @Result INT
SET @Result = 0
SET @Result = @Number1 / @Number2
PRINT '结果是:' + CAST(@Result AS VARCHAR)
END

当我们把0传递给这个存储过程的第二个参数时,我们会得到一个错误

EXEC spDivideTwoNumber 100, 0

以下是 SQL Server Management Studio 中的输出

消息 8134,级别 16,状态 1,过程 spDivideTwoNumber,第 10 行

遇到以零作除数错误。

结果是:0

我们可以看到,即使遇到了错误,SqlServer依然会继续执行后面的语句,最终打印了结果是:0

所以,上述执行的问题在于,即使程序发生错误,它仍然显示结果,因此用户有可能感到困惑。

发生异常时 SQL Server 中会发生什么?

在 SQL Server 中,每当发生异常时,它都会显示异常消息,然后继续执行程序。但在 C#、Java、C++ 等编程语言中,每当发生异常时,程序执行就会在异常发生的那一行异常终止。

在上述案例中,这种行为是错误的,因为当编程语言中发生错误时,它们会直接跳过错误后的所有语句的执行,但是在 SqlServer中发生错误后,执行不会停止。例如,在上面的存储过程中,当异常发生时,它仍然显示不应该发生的 “结果是:0”。

SQL Server 中的异常处理是什么?

随着 SQL Server 2005 中引入 Try/Catch 块,SQL Server 中的错误处理现在与 C# 和 Java 等编程语言非常相似。但是,在了解使用 try/catch 块进行错误处理之前,让我们退后一步,了解在 2005 年之前的 SQL Server 中如何使用系统函数 RAISERROR 和 @@Error 进行错误处理。

在 SQL Server 中使用 RAISERROR 系统函数处理异常

让我们更改我们在上一个示例中创建的相同存储过程,如下所示,以使用 Raiseerror 系统函数来处理 SQL Server 中的异常。

IF OBJECT_ID('spDivideTwoNumber','P') IS NOT NULL
DROP PROCEDURE spDivideTwoNumber
GO
CREATE PROCEDURE spDivideTwoNumber(
@Number1 INT,
@Number2 INT
)
AS
BEGIN
DECLARE @Result INT
SET @Result = 0
IF(@Number2 = 0)
BEGIN
RAISERROR('第二个数字不能为0', 16, 1)
END
ELSE
BEGIN
SET @Result = @Number1 / @Number2
PRINT '结果是: ' + CAST(@Result AS VARCHAR)
END
END

当我们再次执行以下语句时

EXEC spDivideTwoNumber 100, 0

以下是 SQL Server Management Studio 中的输出

消息 50000,级别 16,状态 1,过程 spDivideTwoNumber,第 11 行

第二个数字不能为0

在上述过程中,如果第二个数字为零,我们使用系统定义的 Raiserror () 函数将错误消息返回给调用应用程序。

SQL Server 中的 RaiseError 系统函数是什么?

SQL Server 中的 RaiseError 系统定义函数采用 3 个参数,如下所示。

RAISERROR('错误消息', ErrorSeverity, ErrorState)

  1. 错误消息 :您希望在引发异常时显示的自定义错误消息。
  2. 错误严重性 :当我们在 SQL Server 中返回任何自定义错误时,我们需要将 ErrorSeverity 级别设置为 16,这表明这是一个一般错误,并且该错误可以由用户更正。在我们的示例中,用户可以通过为第二个参数提供非零值来纠正错误。
  3. 错误状态 : ErrorState 也是 1 到 255 之间的整数值。如果您将错误状态值设置在 1 到 127 之间,RAISERROR() 函数只能生成自定义错误。

SQL Server 中的@@Error 系统函数

在 SQL Server 2000 中,为了检测错误,我们使用了@@Error 系统函数。如果有错误,@@Error 系统函数返回一个 NON-ZERO 值,否则,ZERO表示前面的SQL语句执行没有任何错误。让我们修改存储过程以使用@@ERROR系统函数,如下所示。

ALTER PROCEDURE spDivideTwoNumber(
@Number1 INT,
@Number2 INT
)
AS
BEGIN
DECLARE @Result INT
SET @Result = 0
IF(@Number2 = 0)
BEGIN
RAISERROR('第二个数字不能为0',16,1)
END
ELSE
BEGIN
SET @Result = @Number1 / @Number2
END IF(@@ERROR <> 0)
BEGIN
PRINT '发生了错误'
END
ELSE
BEGIN
PRINT '结果是:' + CAST(@Result AS VARCHAR)
END
END

当我们再次执行以下语句时

EXEC spDivideTwoNumber 100, 0

以下是 SQL Server Management Studio 中的输出

消息 50000,级别 16,状态 1,过程 spDivideTwoNumber,第 11 行

第二个数字不能为0

发生了错误

SQL Server 中的预定义错误术语

每当在程序中发生错误,例如将数字除以零、违反主键、违反检查约束等,系统都会显示一条错误消息,告诉我们代码中遇到的问题。程序中发生的每个错误都与四个属性相关联。

  1. 错误编号
  2. 错误信息
  3. 严重程度
  4. 错误状态

比如:

消息 8134(错误编号),级别 16(严重级别),状态 1(状态),遇到除以零错误(错误消息)

  • 错误编号 是为 SQL Server 中发生的每个错误提供的唯一标识符。对于预定义的错误,该值将低于 50,000,对于用户定义的错误,该值必须高于或等于 50,000。在引发自定义错误时,如果我们不指定错误编号,则默认情况下会将错误编号设置为 50000。

  • 错误信息 是描述发生的错误的简短信息,最多 2047 个字符。

  • 严重程度 这说明错误的重要性,范围在 0 到 24 之间。其中

    • 0 到 9:不是服务,可被视为信息或状态消息。
    • 11 到 16: 表示这些错误可以由用户创建。
    • 17 到 19:表示这些是用户无法纠正的软件错误,必须向系统管理员报告。
    • 20 到 24:表示致命错误,如果发生这些错误,可能会损坏系统或数据库。所以这里的连接立即与数据库终止。
  • 错误状态 它是一个不那么重要的任意值,可以在 0 到 127 之间。每当必须在多个地方发生相同的错误时,我们都会使用它。

注意:我们可以在“系统消息”表下找到所有预定义错误的信息

比如:

select * from sys.messages where language_id = 2052 and message_id = 8134

输出如下:

message_id language_id severity is_event_logged text
8134 2052 16 0 遇到以零作除数错误。

SQL Server 中的异常处理的更多相关文章

  1. 在 SQL Server 中使用 Try Catch 处理异常

    如何在 SQL Server 中使用 Try Catch 处理错误? 从 SQL Server 2005 开始,我们在TRY 和 CATCH块的帮助下提供了结构错误处理机制.使用TRY-CATCH的语 ...

  2. SQL Server中的高可用性(2)----文件与文件组

        在谈到SQL Server的高可用性之前,我们首先要谈一谈单实例的高可用性.在单实例的高可用性中,不可忽略的就是文件和文件组的高可用性.SQL Server允许在某些文件损坏或离线的情况下,允 ...

  3. SQL Server中SELECT会真的阻塞SELECT吗?

    在SQL Server中,我们知道一个SELECT语句执行过程中只会申请一些意向共享锁(IS) 与共享锁(S), 例如我使用SQL Profile跟踪会话86执行SELECT * FROM dbo.T ...

  4. Microsoft SQL Server中的事务与并发详解

    本篇索引: 1.事务 2.锁定和阻塞 3.隔离级别 4.死锁 一.事务 1.1 事务的概念 事务是作为单个工作单元而执行的一系列操作,比如查询和修改数据等. 事务是数据库并发控制的基本单位,一条或者一 ...

  5. SQL Server中TOP子句可能导致的问题以及解决办法

    简介      在SQL Server中,针对复杂查询使用TOP子句可能会出现对性能的影响,这种影响可能是好的影响,也可能是坏的影响,针对不同的情况有不同的可能性.      关系数据库中SQL语句只 ...

  6. 在SQL Server中为什么不建议使用Not In子查询

        在SQL Server中,子查询可以分为相关子查询和无关子查询,对于无关子查询来说,Not In子句比较常见,但Not In潜在会带来下面两种问题: 结果不准确 查询性能低下       下面 ...

  7. SQL Server中提前找到隐式转换提升性能的办法

        http://www.cnblogs.com/shanksgao/p/4254942.html 高兄这篇文章很好的谈论了由于数据隐式转换造成执行计划不准确,从而造成了死锁.那如果在事情出现之前 ...

  8. SQL Server中行列转换 Pivot UnPivot

    SQL Server中行列转换 Pivot UnPivot PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PI ...

  9. SQL Server 中使用数据类型表示小数

    在使用的时候发现一个问题,由于编程的习惯,当数据库中需要存储小数的时候,就想当然的使用了float类型,可结果太让人意外了. 数据库中存储了0.5没问题,当使用0.6的时候,得到的确是0.599999 ...

  10. sql server中对xml进行操作

    一.前言 SQL Server 2005 引入了一种称为 XML 的本机数据类型.用户可以创建这样的表,它在关系列之外还有一个或多个 XML 类型的列:此外,还允许带有变量和参数.为了更好地支持 XM ...

随机推荐

  1. ArchLinux安装后常见问题的解决

    Q:UEFI引导grub-install报错:variables are not support on this system A:进入安装u盘的时候是传统引导模式,传统模式下无法安装UEFI启动,解 ...

  2. 最新AI智能体开发案例:Coze工作流必备神器!教你用Coze平台搭建「扣子工作流生成神器」智能体!

    点击 疯狂老包  > 点击右上角"···" > 关注我 各位小伙伴们,大家好呀!我是疯狂老包.我精心打造的<疯狂AI智能体开发:100个实战案例, 从 入门到精通 ...

  3. 为什么在 Python 中 hash(-1) == hash(-2)?

    英文:https://omairmajid.com/posts/2021-07-16-why-is-hash-in-python 作者:Omair Majid 译者:豌豆花下猫&Claude- ...

  4. w3cschool-微信小程序开发文档-服务端

    微信小程序 code2Seesion auth.code2Session 本接口应在服务器端调用,详细说明参见服务端API. 登录凭证校验.通过 wx.login 接口获得临时登录凭证 code 后传 ...

  5. Logstash介绍

    Logstash是一个开源数据收集引擎,具有实时管道功能.Logstash可以动态地将来自不同数据源的数据统一起来,并将数据标准化到你所选择的目的地. 集中.转换和存储你的数据 Logstash是一个 ...

  6. C#/.NET/.NET Core技术前沿周刊 | 第 21 期(2025年1.6-1.12)

    前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录.追踪C#/.NET/.NET Core领域.生态的每周最新.最实用.最有价值的技术文章.社区动态.优质项目和学习资源等. ...

  7. Fanatastic pg walkthrough 10 Easy

    nmap 发现9090 22 和3000端口 发现漏洞 但是不知道还能读到哪些敏感文件 hacktricks 看看 https://book.hacktricks.xyz/network-servic ...

  8. oracle使用存储过程返回游标实现报表查询

    最近在oracle中通过存储过程实现一个报表查询,查询涉及到数据计算这里使用了临时表和存储过程实现输出查询,java接受游标变量返回结果集 第一步.创建统计使用的临时表 CREATE GLOBAL T ...

  9. el-table合计行

    用到属性 showSummary 是否显示合计,方法 summaryMethod 计算合计的自定义方法. <el-table ref="elTable" :data=&quo ...

  10. ClickHouse常用操作

    一.客户端连接1.1 客户端连接ck./clickhouse-client -h 127.0.0.1 --port 9900 -u default --password 123456 -m 1.2 h ...