使用 TRY/CATCH 语句解决 SQL Server 2005 死锁

2023-05-16

对于今天的 RDBMS 体系结构而言,死锁难以避免 在高容量的 OLTP 环境中更是极为普遍。正是由于 .NET 的公共语言运行库 (CLR) 的出现, SQL Server 2005 才得以为开发人员提供一种新的错误处理方法。在本月专栏中, Ron Talmage 为您介绍如何使用 TRY/CATCH 语句来解决一个死锁问题。

一个示例死锁


让我们从这样一个示例开始说起,它在 SQL Server 2000 和 2005 中都能引起死锁。在本文中,我使用 SQL Server 2005 的最新 CTP(社区技术预览,Community Technology Preview)版本,SQL Server 2005 Beta 2(7 月发布)也同样适用。如果您没有 Beta 2 或最新的 CTP 版本,请下载 SQL Server 2005 Express 的最新版本,用它来进行试验。

可能发生的死锁情况有很多,[ 参阅 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/acdata/ac_8_con_7a_3xrf.asp 以及死锁文章树中的后续文章。 编者 ],但最有趣、最微妙的是那些关于阅读器和编写器互相阻塞的死锁。以下代码在 pubs 数据库中就产生了这样一个死锁。(您可以在 SQL Server 2000 的两个 Query Analyzer 窗口中或 SQL Server 2005 的两个 Management Studio queries 中并列运行这段代码。)在其中一个窗口中的代码正文前面添加下列语句:


-- Window 1 header
DECLARE @au_id varchar(11), @au_lname varchar(40)
SELECT @au_id = '111-11-1111', @au_lname = 'test1'
  

在第二个窗口中添加下列语句,进行第二次连接:


-- Window 2 header
DECLARE @au_id varchar(11), @au_lname varchar(40)
SELECT @au_id = '111-11-1112', @au_lname = 'test2'
  

在两个窗口中都使用下列语句作为代码正文:


-- Body for both connections:
BEGIN TRANSACTION
INSERT Authors VALUES 
  (@au_id, @au_lname, '', '', '', '', '', '11111', 0)
WAITFOR DELAY '00:00:05'
SELECT *
  FROM authors
  WHERE au_lname LIKE 'Test%'
COMMIT
  

在第三个窗口中运行下列语句,确保 authors 表格中没有任何包含以下 id 的数据:


DELETE FROM authors WHERE au_id = '111-11-1111'
DELETE FROM authors WHERE au_id = '111-11-1112'
  

在 5 秒钟内同时执行窗口 1 和 窗口 2。因为每个窗口都要等待至少 5 秒钟的时间才能发出 SELECT 语句,所有每个连接都将完成 INSERT 操作,这样就保证了两个窗口中的 INSERT 操作在各自的 SELECT 语句发布前就已经完成了。每个窗口中的 SELECT 语句都尝试读取 authors 表格中的所有数据,查找 au_lname 字段值中类似“Test%”格式的数据。因此,两个窗口中的 SELECT 语句都将尝试读取各自连接中的插入数据 — 也读取对方连接中的插入数据。

READ COMMITTED 隔离级别通过发布共享锁确保 SELECT 语句永远不读取未提交的数据。对于同一个资源,共享锁与排它锁互不兼容,请求者在发布共享锁之前必须等待排它锁释放。每个连接对于插入的数据都设置了排它锁,因此尝试读取对方插入数据的 SELECT 语句将试图解除插入数据的共享锁,但它会被阻塞。两个连接将互相阻塞,从而形成一个死锁。SQL Server 的锁定管理器检测到死锁时,将中止其中的一个批处理,回滚它的事务,释放它的阻塞锁,以便其他事务能够完成。作为死锁牺牲品的事务将回滚,其他事务则将成功完成。

 

如何使用 TRY/CATCH 语句避免死锁


现在,让我们来使用 TRY/CATCH 语句修改代码正文。(对于本示例,需要以 SQL Server 2005 版本运行代码。)使用 TRY/CATCH 时,操作代码和错误处理代码是分开的。您应该将执行一个操作的代码放在 TRY 语句块中,将错误处理代码放在 CATCH 语句块中。如果 TRY 语句块中的代码执行失败,代码执行将跳到 CATCH 语句块。(除了那些防碍整个批处理运行的错误(如,丢失对象),该方法几乎适用于所有的错误。)

以下示例使用 TRY/CATCH 语句对前面使用的代码进行了改写。代码标题相同,但是代码正文不同:


BEGIN TRANSACTION
BEGIN TRY
  INSERT Authors VALUES 
  (@au_id, @au_lname, '', '', '', '', '', '11111', 0)
  WAITFOR DELAY '00:00:05'
  SELECT COUNT(*)  FROM Authors 
  COMMIT
END TRY
BEGIN CATCH
  SELECT ERROR_NUMBER() AS ErrorNumber
  ROLLBACK
END CATCH;
SELECT @@TRANCOUNT AS '@@Trancount'
  

现在,在连接到 SQL Server 2005 的并列窗口中运行这些代码,在此之前您需要确认已经删除了 authors 表格中任何可能阻止插入操作的数据;或者,您可以使用前置 DELETE 语句。

两个窗口返回的 @@TRANCOUNT 级别都为 0,这表明仍然发生了死锁,但 TRY/CATCH 语句捕获了这次发生的死锁。死锁牺牲品的批处理没有再次中止,可在它的输出结果中看到错误:


ErrorNumber
-----------
1205

@@Trancount
-----------
0
  

您应该已经发现 TRY/CATCH 语句具有的威力了。因为死锁错误能够为 CATCH 语句块所捕获,所以批处理将不再中止,T-SQL 代码也能继续执行。对于死锁牺牲品而言,死锁错误 1205 将代码放入 CATCH 语句块 — 在这里您可以使用新的错误处理函数浏览死锁错误。前置代码仅使用 ERROR_NUMBER() 函数取代 @@ERROR 变量,您也可以使用 ERROR_MESSAGE()、ERROR_PROCEDURE()、ERROR_SEVERITY() 和 ERROR_STATE()。这些函数的功能一目了然,它们提供的功能比我们以往使用的更多。

请注意,这个前置 CATCH 语句块包含一个 ROLLBACK。这样做的原因是,即使捕获了死锁错误,事务也不会回滚。事务仍然要失败,但是,现在您有责任在 TRY/CATCH 语句中回滚事务。那么,区别在哪里?尽管您不能使事务继续进行,但是您能够 重试事务!

 

在 TRY/CATCH 语句中进行重试


在 SQL Server 2000 的 T-SQL 中,错误 1205 令人沮丧之处是它提供的建议:“Rerun the transaction.”问题是,至少在 SQL Server 2000 的 T-SQL 中,您不能做到这一点。但是,由于 SQL Server 2005 的 TRY/CATCH 为我们提供了捕获死锁错误的方法,现在,重试事务是可能 实现的。

以下代码正文说明了一种执行重试操作的方法。这段代码仍然使用与前面相同的标题:


DECLARE @Tries tinyint
SET @Tries = 1
WHILE @Tries <= 3
BEGIN
  BEGIN TRANSACTION
  BEGIN TRY
    INSERT Authors VALUES 
      (@au_id, @au_lname, '', '', '', '', '', 
'11111', 0)
    WAITFOR DELAY '00:00:05'
    SELECT * FROM authors WHERE au_lname LIKE 'Test%'
    COMMIT
    BREAK
  END TRY
  BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber
    ROLLBACK
    SET @Tries = @Tries + 1
    CONTINUE
  END CATCH;
END
  

这段代码的功能是通过一个 WHILE 循环添加一个重试操作。我将重试次数设置为 3,重试次数是可以配置的。至少我们现在有了一种在 T-SQL 内重试一个死锁牺牲品代码的方法 — 这是我们过去一直无法做到的。

但是,需要注意整个事务是在 WHILE 循环内进行的 — 而不是在循环外部。因此执行循环时,事务不仅在每个循环体内部开始,而且也在其中结束 — 不是 TRY 语句块执行完毕,返回一个 COMMIT,就是 CATCH 语句块执行,返回一个 ROLLBACK。如果 TRY 成功,TRY 语句块将以一个 BREAK 语句结束,退出 WHILE 循环。否则,CATCH 语句块将重试计数器加 1,以一个 CONTINUE 语句结束本次循环,重新执行下次 WHILE 循环。事实上,您有实现重试事务的代码 — 就像错误 1205 告诉我们做的那样。但现在,重试操作完全在 T-SQL 内部完成。

SQL Server 2005 也提供帮助解决死锁问题的其他方法,例如 SNAPSHOT ISOLATION 级别和用于 READ COMMITTED 的新选项(称为 READ COMMITTED SNAPSHOT)。然而,这一事实 — 现在,通过 SQL Server 2005,您能够对事务进行编码并捕获死锁错误(并重试它们) — 已经意味着您拥有一个可任意支配、功能更加强大的工具。

下载:单击下载按钮来下载代码 (505RON.SQL)

要查找有关 SQL Server Professsional 和 Pinnacle Publishing 的信息,请访问它们的 Web 站点 http://www.pinpub.com/

注:这个网站不是 Microsoft Corporation 的 Web 站点。Microsoft 对该网站的内容不承担责任。

本文转自 SQL Server Professsional 的 2005 年 5 月刊。Copyright 2005 为 Pinnacle Publishing, Inc. 所有,除非另行说明。保留所有权利。SQL Server Professsional 是 Pinnacle Publishing, Inc 的独立出版物。未经 Pinnacle Publishing, Inc 事先同意,不得以任何形式(除了在评论文章中作为简短引用)使用或复制本文。要与 Pinnacle Publishing, Inc. 联系,请您拨打电话 1-800-788-1900。

转载于:https://www.cnblogs.com/programmingsnail/archive/2009/10/12/1581574.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 TRY/CATCH 语句解决 SQL Server 2005 死锁 的相关文章

  • 在 Oracle 中创建数据库链接时出错

    我有两个数据库 需要编写跨数据库查询 所以我试图创建一个数据库链接 CREATE PUBLIC DATABASE LINK DBLink CONNECT TO SchemaName IDENTIFIED BY 123 using DBNam
  • 动态/条件 SQL 连接?

    我在 MSSQL 表 TableB 中有数据 其中 dbo tableB myColumn 在特定日期后更改格式 我正在做一个简单的连接到该表 Select dbo tableB theColumnINeed from dbo tableA
  • MySQL:用户对数据库的访问被拒绝

    我正在尝试在 Heroku 上的远程 SQL 服务器上创建一个数据库 clearDB 我与此联系 mysql host lt
  • 在 C# 中多次使用单个参数的更好方法

    我刚开始使用准备好的语句从数据库查询数据 并且在实现 C 参数 特别是 OracleParameters 时遇到问题 假设我有以下 SQL string sql select from table1 t1 table2 t2 where t
  • 显示多个表的账户余额

    我有以下两个表 其中存储有关贷记和借记记录的信息 couponCr 表包含 voucherType voucherPrefix voucherNo crparty cramount SALES S 1 1 43000 SALES S 2 1
  • SQL Not Empty 代替 Not NULL

    我正在使用 postgreSQL 我有一个专栏 NOT NULL 但是 当我想插入带有空字符串的行时 如下所示 它不会给我错误并接受 我如何检查插入值应该是not empty 既不为空也不为空 PS 我的专栏定义为 ads characte
  • 单向关系和双向关系的区别

    我想知道这两个词是什么意思 我遇到他们是在教义的文档 http www doctrine project org documentation manual 2 0 en association mapping 但我不明白他们的意思 这与常见
  • 如何比较表中最后一个和倒数第二个条目的值?

    我在 Oracle 中有一个名为quotes 的表 其中包含两列 date 和value 我想比较表中最后一个条目和倒数第二个条目的值 在此示例中 我想获取日期13 1 和 11 1在一行中以及每个日期的值之间的差异 10 5 5 报价表
  • 规范“毒”方式真的值得吗? (3NF)

    我正处于数据库设计的早期阶段 所以还没有最终的结果 并且我正在为具有可选标签的线程使用 TOXI 3表设计 但我忍不住觉得加入是并不是真的必要 也许我只需要依赖我的简单标签列posts我可以在其中存储类似 varchar 的表
  • MS Access:在列中搜索星号/星号

    我正在寻找一种方法来搜索包含字符串数据类型的列 问题是星号或星号是保留符号 以下查询无法正常工作 select from users where instr pattern 如何编写 Access 查询来搜索列中的星号 您可以使用方括号在
  • 如何在sql中提取周数

    我有一个 varchar2 类型的转换列 其中包含以下主菜 01 02 2012 01 03 2012 etc 我使用 to date 函数将其转换为另一列中的日期格式 这是我得到的格式 01 JAN 2012 03 APR 2012 当我
  • 动态 SQL 和 where case 哪个更好?

    我需要创建一个带有 12 个参数的存储过程 并使用这些参数的不同组合来过滤查询 所有 12 个参数都不是强制性的 就好像我传递 3 5 或 12 个参数取决于用户输入的搜索输入一样 我可以通过两种方式创建 即使用动态 SQL 查询或使用 C
  • 无法将方法组“Read”转换为非委托类型“bool”

    我正在尝试使用SqlDataReader检查条目是否存在 如果存在则返回ID 否则返回false 当我尝试编译时 出现错误 无法将方法组 Read 转换为非委托类型 bool 我一直在遵循在 VB 中找到的示例 但似乎翻译可能不正确 pri
  • 如何在可能为空值的字段上创建唯一索引(Oracle 11g)?

    这是包含 3 列的示例表 ID UNIQUE VALUE UNIQUE GROUP ID 我希望可以允许以下记录 1 NULL NULL 2 NULL NULL or 3 NULL 7 4 123 7 or 注意 此条件不允许unique
  • count 和 groupby 在一个查询中一起使用

    以下查询正在获取页面上的一些产品信息 这很好 但我也想以文本形式显示它出现的产品编号 但是 我使用了groupby但我也想用count on pro id SELECT FROM cart WHERE session id SESSION
  • 如何在 postgreSQL 中从时间戳中减去/添加分钟

    我有以下场景 我有员工登记他们的上班 下班手续 但他们有10分钟的容忍度 我通过这种观点得到的最新条目 CREATE OR REPLACE VIEW employees late entries id created datetime en
  • ORDER BY id 或 date_created 显示最新结果?

    我有一个表 实际上有几个 我想首先从中获取最新条目的结果 这是我的ORDER BY条款选项 date created INT 从不改变值 id 当然是INT AUTO INCRMENT 两列应同等地代表记录插入的顺序 我自然会使用date
  • 如何对主索引重新编号

    我有一个简单的 MySQL 表 主索引 id 不是一一编号的 1 31 35 100 等 我希望它们的编号如 1 2 3 4 请告诉我该怎么做 我还想指出的是 我知道该操作可能产生的后果 但我只是想整理一下表格 我同意其他方法也可以 但我只
  • Java/Hibernate - 异常:内部连接池已达到其最大大小,当前没有可用的连接

    我第一次在大学项目中使用 Hibernate 而且我还是个新手 我想我遵循了我的教授和我阅读的一些教程给出的所有指示 但我不断收到标题中的异常 Exception in thread main org hibernate Hibernate
  • 扁平化/反规范化 SQL 查找表的最佳方法?

    我有很多这样的表 Lookup HealthCheckupRisks ID Name 1 Anemia 2 Anorexic 3 Bulemic 4 Depression 122 Syphilis PatientRisksOnCheckup

随机推荐

  • 推荐 3 款实用 Node.js 版本管理工具

    为了能够对 Node js 版本进行版本管理 xff0c 我整理了 3 款非常实用的 Node js 版本管理工具 xff0c 让大家能够自由地切换本地环境不同的 Node js 版本 1 nvm Github stars 60K 43 n
  • ipv6 neutron应用(一)

    一 neutron支持ipv6 xff0c 有2个重要的属性 1 ipv6 ra mode 2 ipv6 address mode 这2个属性都可以设置下面三个值 1 slaac 2 dhcpv6 stateful 3 dhcpv6 sta
  • 理解Compressed Sparse Column Format (CSC)

    最近在看 Spark for Data Science 这本书 xff0c 阅读到 Machine Learning 这一节的时候被稀疏矩阵的存储格式CSC给弄的晕头转向的 所以专门写一篇文章记录一下我对这种格式的理解 目的 Compres
  • FBOSS

    https github com facebook fboss
  • 五款针对Ubuntu系统的最佳杀毒软件

    随着使用 Linux 作为主要桌面的用户越来越多 xff0c 很多黑手都伸向了这部分用户 虽然目前专门针对 Linux 的专有恶意软件还比较少 xff0c 但大家还是需要保持相当的谨慎才是才策 由于大部分 Linux 新手用户中 Ubunt
  • 解决www.github.com访问太慢的问题

    解决www github com访问太慢的问题 使用www github com的过程中 xff0c 有时候打开会特别的慢 xff0c 原因github com的域名被一堵伟大的墙挡在了外面 但是我们可以通过修改本机的hosts文件来修改这
  • 国内有哪些好的刷题网站?

    http www zhihu com question 25574458 Luau Lawrence xff0c Data Mining 弱鸡 PhD 64 NTU 温梦强 石一帆 知乎用户 等人赞同 Welcome To PKU Judg
  • 使用update命令来修改Mysql的root密码

    1 xff0c 使用update命令来修改Mysql的root密码 使用Mysql update命令既可以修改root的老密码 xff0c 也可设置root的密码为空 xff0c 如果使用update命令更改root的密码 xff0c 需要
  • 设置 java -jar 的进程显示名称

    有时候我们会用 nohup java jar xxx jar 来将一些可执行的java application挂在后台 xff0c 类似windows服务一样来运行 但是有一个不爽的地方 xff0c 在linux终端里用jps 显示时 xf
  • linux下修改hostid

    linux下修改hostid 网上有很多版本 xff0c 总结了这几点 1 gt 一个以16进制显示的int字符串 xff1b 2 gt 配置文件 etc hostid 如果有值 xff0c 输出 xff0c 结束 3 gt 从hostna
  • 21分钟学会写编译器

    本文来自网易云社区 知乎上有一种说法是 编译器 图形学 操作系统是程序员的三大浪漫 先不管这个说法是对是错 xff0c 我们假设一个程序员在国内互联网公司写代码 xff0c 业余时间不看相关书籍 那么三年之后 xff0c 他的这些知识会比在
  • 解决idea打包出现中文乱码的问题

    这主要是maven编译时编码问题导致的 在Intellij的settings中maven的runner配置中将原有的配置 DarchetypeCatalog 61 internal修改设置它的VM Options为 DarchetypeCa
  • 局部使用element-ui自定义主题实践

    背景 内部系统虽然使用了element ui xff0c 但同时又混杂了多种风格的样式和各自写的通用组件 xff0c 在参与新功能开发时 xff0c 产品经理的设计需要以绿色为主题色 xff0c 看到element官网有个自定义主题 xff
  • windows server 2012 R2 远程桌面授权模式尚未配置

    windows server 2012 R2 远程桌面授权模式尚未配置 xff0c 远程桌面服务将在120天内停止工作 如何破解这个宽限期 xff0c 目前企业7位协议号码均不包含2012 R2以上授权 那么只能蛋疼的 破解 咯 解决方法
  • LPAD

    语法 span class pln style color rgb 0 0 0 VARCHAR LPAD span span class pun style color rgb 102 102 0 span span class pln s
  • Python 之 sqlalchemy更新数据

    表结构 xff1a 代码 xff1a Author Kang import sqlalchemy from sqlalchemy import create engine from sqlalchemy ext declarative im
  • php curl 设置请求头headers和请求体body

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 啥也不说 xff0c 直接上代码 我这里是post请求 url 61 34 http www example com 34 headers数组内的格式 headers 61
  • 华为路由器双出口负载均衡+备份

    一个网段内 xff0c IP地址 xff08 末位奇数 xff09 走电信 xff0c IP地址 xff08 末位偶数 xff09 走联通 当某个运营商不可达时 xff0c 自动切换 通过NQA来确定运营商是否可达 xff0c 并与流行为
  • office2013VOL版下载资源链接

    office2013VOL版下载资源链接 软件名称 xff1a office2013VOL软件大小 xff1a 914 5 810 7 713 3 801 2 M 软件语言 xff1a 简中软件性质 xff1a 免费 xff08 需要mak
  • 使用 TRY/CATCH 语句解决 SQL Server 2005 死锁

    对于今天的 RDBMS 体系结构而言 xff0c 死锁难以避免 在高容量的 OLTP 环境中更是极为普遍 正是由于 NET 的公共语言运行库 CLR 的出现 xff0c SQL Server 2005 才得以为开发人员提供一种新的错误处理方