群里一个朋友遇到一个TRY CATCH的小问题,测试后发现是自己从来没有考虑的情况,写篇blog加深下印象

--=========================================================

在MSDN上对TRY CATCH有如下描述:

对 Transact-SQL 实现与 Microsoft Visual C# 和 Microsoft Visual C++ 语言中的异常处理类似的错误处理。Transact-SQL 语句组可以包含在 TRY 块中。如果 TRY 块内部发生错误,则会将控制传递给 CATCH 块中包含的另一个语句组。

--=========================================================

在TRY CATCH未出现之前,我们使用@@ERROR,ERROR_STATE()等来判断语句是否正常运行,再根据情况来处理事务,随着TRY CATCH的出现,我们可以将事务语句写成如下方式:

--开启事务
BEGIN TRAN
BEGIN TRY
--执行一些逻辑操作
INSERT INTO TB1(ID)VALUES(1)
--提交事务
COMMIT TRAN
END TRY
BEGIN CATCH
--回滚事务
ROLLBACK TRAN
END CATCH

可当我们执行以下语句(不创建临时表#TB)

BEGIN TRAN
BEGIN TRY INSERT INTO #TB SELECT 1 PRINT 'COMMIT TRAN'; COMMIT TRAN;
END TRY
BEGIN CATCH SELECT ERROR_MESSAGE() AS ErrorMessage
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState PRINT 'ROLLBACK TRAN';
ROLLBACK TRAN; END CATCH

由于#TB没有创建,因此在执行中发生异常,错误提示如下:

消息 102,级别 15,状态 1,第 24 行
“对”附近有语法错误。

这个错误很容易理解,因为#TB不存在,但这不是重点,重点是CATCH部分的语句没有被执行,事务没有被提交也没有被回滚(如果程序中有类似问题,那就严重咯)。

继续阅读MSDN,可以找到如下解释:

不受 TRY…CATCH 构造影响的错误
TRY…CATCH 构造在下列情况下不捕获错误: 严重级别为 10 或更低的警告或信息性消息。 严重级别为 20 或更高且终止会话的 SQL Server 数据库引擎任务处理的错误。如果所发生错误的严重级别为 20 或更高,而数据库连接未中断,则 TRY…CATCH 将处理该错误。 需要关注的消息,如客户端中断请求或客户端连接中断。 当系统管理员使用 KILL 语句终止会话时。 如果以下类型的错误的发生级别与 TRY…CATCH 构造的执行等级相同,则 CATCH 块不会处理这些错误: 编写错误,例如禁止运行批处理的语法错误。 语句级重新编写过程中出现的错误,例如由于名称解析延迟而造成在编写后出现对象名解析错误。 这些错误会被返回到运行批处理、存储过程或触发器的级别。

经过对比分析,我们遇到的问题应该属于“语句级重新编写过程中出现的错误,例如由于名称解析延迟而造成在编写后出现对象名解析错误。”的情况。

--==============================================================

如果有类似的问题,我们应该如何处理呢?

解决办法1: 在对#TB处理前先判断其是否存在

解决办法2:将对#TB的操作语句放入的EXEC(@SQL)

BEGIN TRAN
BEGIN TRY EXEC('INSERT INTO #TB SELECT 1') PRINT 'COMMIT TRAN'; COMMIT TRAN;
END TRY
BEGIN CATCH SELECT ERROR_MESSAGE() AS ErrorMessage
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState PRINT 'ROLLBACK TRAN';
ROLLBACK TRAN; END CATCH

执行以上代码,会发现同样是严重级别16的错误,这次可以被传递到CATCH块中处理。
--=======================================================

很多人说细节决定成败,学习SQL SERVER的路上,有很多类似的小知识点,平时很难遇到,遇到时也很容易颠覆下我们自认为的“真理”,这个时候,多看看MSDN还是很管用的!

曲演杂坛--使用TRY CATCH应该注意的一个小细节的更多相关文章

  1. 曲演杂坛--一条DELETE引发的思考

    原文:曲演杂坛--一条DELETE引发的思考 场景介绍: 我们有一张表,专门用来生成自增ID供业务使用,表结构如下: CREATE TABLE TB001 ( ID ,) PRIMARY KEY, D ...

  2. 曲演杂坛--蛋疼的ROW_NUMBER函数

    使用ROW_NUMBER来分页几乎是家喻户晓的东东了,而且这东西简单易用,简直就是程序员居家必备之杀器,然而ROW_NUMBER也不是一招吃遍天下鲜的无敌BUG般存在,最近就遇到几个小问题,拿出来供大 ...

  3. 曲演杂坛--当ROW_NUMBER遇到TOP

    值班期间研发同事打来电话,说应用有超时,上服务器上检查发现有SQL大批量地执行,该SQL消耗IO资源较多,导致服务器存在IO瓶颈,细看SQL,发现自己都被整蒙了,不知道这SQL是要干啥,处理完问题赶紧 ...

  4. 曲演杂坛--特殊字符/生僻字与varchar

    对于中文版的SQL SERVER,默认安装后使用的默认排序规则为Chinese_PRC_CI_AS,在此排序规则下,使用varchar类型来可以“正常存取”存放中文字符以及一些东南亚国家的字符,同时v ...

  5. 曲演杂坛--使用CTE时踩的小坑:No Join Predicate

    在一次系统优化中,意外发现一个比较“坑”的SQL,拿出来供大家分享. 生成演示数据: --====================================== --检查测试表是否存在 IF(O ...

  6. 曲演杂坛--为什么SELECT语句会被其他SELECT阻塞?

    很多刚入门的DBA在捕获阻塞得时候,会问这么一个问题“为什么这个SELECT语句被那个SELECT语句阻塞了,难道不是共享锁么?” 让我们来做个小测试,首先准备一些测试数据: --========== ...

  7. 曲演杂坛--EXISTS语句

    通常在我写EXISTS语句时,我会写成IF EXISTS(SELECT TOP(1) 1 FROM XXX),也没细细考究过为什么要这么写,只是隐约认为这样写没有啥问题,那今天就深究下吧! 首先准备测 ...

  8. 曲演杂坛--SQLCMD下执行命令失败但没有任何错误提示的坑

    今天使用SQLCMD导入到SQL SERVER数据库中,看着数据文件都成功执行,但是意外发现有一个文件数据没有成功导入,但执行不报错,很容易导致问题被忽略. 使用存在问题的文件做下测试,从界面上看几行 ...

  9. 曲演杂坛--Update的小测试

    今天偶然想起一个UPDATE相关的小问题,正常情况下,如果我们将UPDATE改写成与之对应的SELECT语句,其SELECT查询结果应与UPDATE的目标表存在一对一的关系,例如: 对于UPDATE语 ...

随机推荐

  1. Windows XP with SP3大客户免激活日文版

    原贴地址:http://www.humin.com.cn/ja_windows_xp_professional_with_service_pack_3_x86_dvd_vl_x14-74058-iso ...

  2. 'org.springframework.beans.factory.xml.XmlBeanFactory' is deprecated

    'org.springframework.beans.factory.xml.XmlBeanFactory' is deprecated XmlBeanFactory这个类已经被摒弃了.可以用以下代替 ...

  3. Partition List双色问题链表版

    [抄题]: Given a linked list and a value x, partition it such that all nodes less than x come before no ...

  4. Visual Event查看页面相关绑定事件

    页面相关绑定的事件比较复杂,在不熟悉的情况下很难找到相关逻辑的位置,所以希望借助工具来帮自己理清相关事件的脉络走向. 浏览器 工具 chrome( 58.0.3029.110) Visual Even ...

  5. dede 复制文章,远程图片无法本地化

    解决方法: 1.找到dede的后台目录,在后台目录下的inc下找到inc_archives_functions.php 2.搜索GetCurContent函数,找到如下这段代码: preg_match ...

  6. SqlServer中批量update

    现在我有两张表分别是S_PERSON,S_USER S_PERSON S_USER 我现在想把S_USER表中的ACCOUNT批量修改成S_PERSON的ACCOUNT 我们可以发现S_USER表中有 ...

  7. Golang之go 命令用法

    Go 命令 Go 命令 Go语言自带有一套完整的命令操作工具,你可以通过在命令行中执行go来查看它们: 图1.3 Go命令显示详细的信息 这些命令对于我们平时编写的代码非常有用,接下来就让我们了解一些 ...

  8. pkg_config找不到库

    解决方法 假设libavutil默认安装时libavutil.pc安装到了 /usr/lib64/lib/pkgconfig/ 中,而 echo $PKG_CONFIG_PATH 结果中没有这个路径, ...

  9. Core Dump 程序故障分析

    1.编写一个应用程序,使用gdb+core dump进行故障分析, core dump的概念: core dump又叫核心转存:当程序在运行过程中发生异常,这时Linux系统可以把程序在运行时的内存内 ...

  10. 如果程序集是从 Web 上下载的,即使它存储于本地计算机,Windows 也会将其标记为 Web 文件,http://go.microsoft.com/fwlink/?LinkId=179545

    使用Silverlight,经常弄出很多莫名的XXX文件来于Web,神马信任程序集,就Build个程序都那么麻烦,应该在所有发布时注明一些最基本的配置说明,最BT莫过于连下载程序集的地方都找不到. 若 ...