热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

设计无SQL死锁的编码模式-AchievingSQLDeadlock-FreeDesign

在运行于MSSQLServer2005的.NET2.0Web应用中,我偶尔会遇到令人头疼的SQL死锁问题。过去,我们主要通过调整查询来解决这些问题,但这既耗时又不可靠。我希望能找到一种确定性的查询模式,确保从设计上彻底避免SQL死锁。

在我运行于MS SQL Server 2005的.NET 2.0 Web应用中,偶尔会遇到令人头疼的SQL死锁问题。过去,我们主要通过调整查询来解决这些问题,但这既耗时又不可靠。我希望找到一种确定性的查询模式,确保从设计上彻底避免SQL死锁。

例如,在C#多线程编程中,一个简单的设计规则是按字典顺序获取锁,这可以确保不会发生死锁。那么,SQL中是否有类似的编码模式可以保证无死锁呢?

解决方案

#1

编写防死锁代码非常困难。即使以相同的顺序访问表,仍然可能会遇到死锁。我在博客中详细讨论了一些方法,可以帮助避免和解决死锁情况。如果您希望确保两个语句/事务不会死锁,可以使用sp_lock系统存储过程观察每个语句使用的锁,但必须非常迅速或使用带有HOLDLOCK提示的开放事务。

#2

在一般情况下,零死锁是一个非常昂贵的问题,因为您必须知道每个运行事务将读取和修改的所有表/对象(包括SELECT语句)。常见的解决方法是有序严格的两阶段锁(2PL),但即使是2PL也不能保证无死锁。很少有DBMS实现严格的2PL,因为这会导致大量性能损失。您可以考虑调整SQL Server中的隔离级别,例如使用快照隔离或读未提交隔离级别。

#3

没有通用的解决方案可以完全避免死锁。您可以将并发控制移到应用程序层面,但这可能非常复杂,尤其是需要与其他程序协调时。一些减少死锁机会的一般方法包括:基本查询优化、热点回避设计、尽量缩短事务时间、设置合理的查询超时等。

#4

在某些限制条件下,以下读/写模式可以防止死锁:

  • 约束:
    • 一个表
    • 使用索引或主键进行读/写,避免表锁
    • 可以使用单个SQL WHERE子句读取一批记录
    • 使用SQL Server术语
  • 写周期:
    • 所有写操作在一个“读提交”事务中
    • 事务中的第一个更新是针对每个更新组中特定的、始终存在的记录
    • 随后可以以任何顺序写入多个记录
  • 读周期:
    • 默认读提交事务级别
    • 无事务
    • 将记录作为一个选择语句读取
  • 好处:
    • 二级写周期在第一个记录的写入过程中被阻塞,直到第一个写事务完全完成
    • 在写提交之间,读取被阻塞/排队/自动执行
    • 无需使用“可序列化”即可实现事务级别的一致性

#5

始终以相同的顺序访问表是避免死锁的好方法。此外,尽可能缩短事务时间。另一个技巧是尽可能将两个SQL语句组合成一个。单个语句总是事务性的。例如,使用“UPDATE ... SELECT”或“INSERT ... SELECT”,使用“@@ERROR”和“@@ROWCOUNT”代替“SELECT COUNT”或“IF (EXISTS ...)”。最后,确保调用代码可以通过重新发布查询的可配置次数来处理死锁。

#6

除了一致的锁获取顺序,还可以显式使用锁和隔离提示,以减少在读取过程中无意地获取锁(如共享意图)所浪费的时间/资源。

#7

对于SQL Server,许多锁定问题可以通过正确的覆盖索引来消除。这是因为它可以大大减少对表的聚集索引的书签查找,从而减少争用和锁定。

#8

如果您对应用程序有足够的设计控制,可以将更新/插入限制在特定的存储过程中,并从应用程序使用的数据库角色中删除更新/插入权限(仅显式允许通过这些存储过程进行更新)。将数据库连接隔离到应用程序中的特定类(每个连接必须来自这个类),并指定“仅查询”连接将隔离级别设置为“脏读”。

#9

没有绝对保证的技术可以避免死锁。如果您预先锁定流程中可能需要的所有资源,即使最终不需要这些资源,也可能导致第二个进程等待获取所需的第一个锁,从而影响可用性。解决SQL死锁问题的最佳方法是查看分析器中的工作负载并理解其行为。

#10

虽然不是直接回答您的问题,但“用餐哲学家问题”是一个经典的死锁问题思想实验。阅读相关内容可能会帮助您找到解决特定问题的方法。


推荐阅读
  • andr ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • MongoDB集群配置:副本集与分片详解
    本文详细介绍了如何在MongoDB中配置副本集(Replica Sets)和分片(Sharding),并提供了具体的步骤和命令,帮助读者理解并实现高可用性和水平扩展的MongoDB集群。 ... [详细]
  • 如何在PHPCMS V9中实现多站点功能并配置独立域名与动态URL
    本文介绍如何在PHPCMS V9中创建和管理多个站点,包括配置独立域名、设置动态URL,并确保各子站能够正常运行。我们将详细讲解从新建站点到最终配置路由的每一步骤。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • MySQL 数据库迁移指南:从本地到远程及磁盘间迁移
    本文详细介绍了如何在不同场景下进行 MySQL 数据库的迁移,包括从一个硬盘迁移到另一个硬盘、从一台计算机迁移到另一台计算机,以及解决迁移过程中可能遇到的问题。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • CentOS7源码编译安装MySQL5.6
    2019独角兽企业重金招聘Python工程师标准一、先在cmake官网下个最新的cmake源码包cmake官网:https:www.cmake.org如此时最新 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 本文深入探讨 MyBatis 中动态 SQL 的使用方法,包括 if/where、trim 自定义字符串截取规则、choose 分支选择、封装查询和修改条件的 where/set 标签、批量处理的 foreach 标签以及内置参数和 bind 的用法。 ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • 本文详细介绍了C语言中链表的两种动态创建方法——头插法和尾插法,包括具体的实现代码和运行示例。通过这些内容,读者可以更好地理解和掌握链表的基本操作。 ... [详细]
  • 在维护公司项目时,发现按下手机的某个物理按键后会激活相应的服务,并在屏幕上模拟点击特定坐标点。本文详细介绍了如何使用ADB Shell Input命令来模拟各种输入事件,包括滑动、按键和点击等。 ... [详细]
  • 解决Element UI中Select组件创建条目为空时报错的问题
    本文介绍如何在Element UI的Select组件中使用allow-create属性创建新条目,并处理创建条目为空时出现的错误。我们将详细说明filterable属性的必要性,以及default-first-option属性的作用。 ... [详细]
author-avatar
悸末丶C彼岸花开
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有