在 SQL Server 2005 上违反 INSERT WHERE COUNT(*) = 0 上的 UNIQUE KEY 约束

2023-12-31

我正在从多个进程插入 SQL 数据库。这些进程有时可能会尝试将重复数据插入表中。我尝试以处理重复项的方式编写查询,但我仍然得到:

System.Data.SqlClient.SqlException: Violation of UNIQUE KEY constraint 'UK1_MyTable'. Cannot insert duplicate key in object 'dbo.MyTable'.
The statement has been terminated.

我的查询看起来像这样:

INSERT INTO MyTable (FieldA, FieldB, FieldC)
SELECT FieldA='AValue', FieldB='BValue', FieldC='CValue'
WHERE (SELECT COUNT(*) FROM MyTable WHERE FieldA='AValue' AND FieldB='BValue' AND FieldC='CValue' ) = 0

约束“UK1_MyConstraint”表示在 MyTable 中,3 个字段的组合应该是唯一的。

我的问题:

  1. 为什么这不起作用?
  2. 我需要进行哪些修改才能避免因违反约束而出现异常?

请注意,我知道还有其他方法可以解决“如果不存在则插入”的原始问题,例如(总而言之):

  • 使用 TRY CATCH
  • IF NOT EXIST INSERT(在具有可序列化隔离的事务内)

我应该使用其中一种方法吗?

Edit 1创建表的SQL:

CREATE TABLE [dbo].[MyTable](
  [Id] [bigint] IDENTITY(1,1) NOT NULL,
  [FieldA] [bigint] NOT NULL,
  [FieldB] [int] NOT NULL,
  [FieldC] [char](3) NULL,
  [FieldD] [float] NULL,
  CONSTRAINT [PK_MyTable] PRIMARY KEY NONCLUSTERED 
  (
    [Id] ASC
  )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON),
  CONSTRAINT [UK1_MyTable] UNIQUE NONCLUSTERED 
  (
    [FieldA] ASC,
    [FieldB] ASC,
    [FieldC] ASC
  )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON)
)

Edit 2决定:

只是为了更新这一点 - 我决定使用链接问题中建议的“JFDI”实施(link https://stackoverflow.com/questions/3407857/only-inserting-a-row-if-its-not-already-there/3408196#3408196)。尽管我仍然很好奇为什么最初的实现不起作用。


为什么这不起作用?

我相信 SQL Server 的默认行为是在不再需要共享锁时立即释放它们。您的子查询将导致表上出现短期共享 (S) 锁,该锁将在子查询完成后立即释放。

此时,没有什么可以阻止并发事务插入您刚刚验证的不存在的行。

我需要进行哪些修改才能避免因违反约束而出现异常?

添加HOLDLOCK对子查询的提示将指示 SQL Server 保留锁定,直到事务完成。 (在您的情况下,这是隐式事务。)HOLDLOCK提示相当于SERIALIZABLE提示,它本身相当于您在“其他方法”列表中引用的可序列化事务隔离级别。

The HOLDLOCK仅提示就足以保留 S 锁并防止并发事务插入您要防范的行。但是,您可能会发现唯一的密钥冲突错误被死锁取代,并且以相同的频率发生。

如果您只保留表上的 S 锁,请考虑插入同一行的两次并发尝试之间的竞争,以锁步方式进行 - 两者都成功获取表上的 S 锁,但都无法成功获取独占锁(X) 执行插入所需的锁。

幸运的是,还有另一种锁类型适合这种情况,称为更新 (U) 锁。 U 锁与 S 锁相同,但有以下区别:同一资源上可以同时持有多个 S 锁,但一次只能持有一个 U 锁。 (换句话说,虽然 S 锁彼此兼容(即可以在没有冲突的情况下共存),但 U 锁彼此不兼容,但可以与 S 锁共存;更进一步,排他 (X) 锁则不可以与 S 或 U 锁兼容)

您可以使用以下命令将子查询上的隐式 S 锁升级为 U 锁:UPDLOCK hint.

现在,在表中插入同一行的两次并发尝试将在初始 select 语句处序列化,因为这会获取(并持有)一个 U 锁,而该 U 锁与并发插入尝试中的另一个 U 锁不兼容。

空值

FieldC 允许 NULL 值这一事实可能会引起一个单独的问题。

If ANSI_NULLS开启(默认)则相等性检查FieldC=NULL即使在 FieldC 为 NULL 的情况下也会返回 false(您必须使用IS NULL运算符检查 null 时ANSI_NULLS已开启)。由于 FieldC 可为空,因此在插入 NULL 值时,重复检查将不起作用。

要正确处理空值,您需要修改 EXISTS 子查询以使用IS NULL运算符而不是=当插入 NULL 值时。 (或者您可以更改表以禁止所有相关列中出现 NULL。)

SQL Server 联机书籍参考

  • 锁定提示 http://msdn.microsoft.com/en-us/library/ms187373.aspx
  • 锁兼容性矩阵 http://msdn.microsoft.com/en-us/library/ms186396.aspx
  • ANSI_NULLS http://msdn.microsoft.com/en-us/library/ms188048.aspx
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 SQL Server 2005 上违反 INSERT WHERE COUNT(*) = 0 上的 UNIQUE KEY 约束 的相关文章

随机推荐

  • Fabric.js - 无需按住鼠标按钮即可移动对象

    在 Fabric js 中 可以通过左键单击 按住并移动鼠标在画布中移动对象 在这种情况下 所选对象会跟随鼠标光标移动并object moving被解雇 释放鼠标左键可退出此模式 有没有办法改变这种行为并让对象通过不同的事件进入这种模式 例
  • Metro 捆绑程序:错误:EISDIR:对目录进行非法操作,读取

    当我重新加载我的包时 这个异常未被捕获 Error EISDIR illegal operation on a directory read at Object readSync fs js 592 3 at tryReadSync fs
  • 从 Runnable 返回值

    我花了几天时间试图解决这个问题 但我不能 解决这个问题的方法是去 StackOverflow D 碰巧我正在使用 libgdx 制作游戏的库 并且在 Android 中查询代码是通过Handler http developer androi
  • 带有自动完成材质 UI 的 React Form Hook

    我有一个countries数组包含id and name 目前我正在使用 Material UIAutocomplete元素和我有一个反应钩子形式 当我提交表单时 我想获取国家 地区 ID 目前它正在发布国家名称 有没有一种方法可以发布 i
  • 了解 Android:Zygote 和 DalvikVM

    我想了解 Android 如何启动应用程序 问题是 Zygote 如何 以及为什么 分叉一个新的 Dalvik VM 我不明白为什么不能在同一个 Dalvik VM 中运行多个应用程序 问 zygote 是如何精确分叉 Dalvik VM
  • AngularJS - 如何在不提交表单的情况下使用 ng-click?

    我有一个同时具有 ng click 和 ng submit 的表单 ng submit 用于提交 而 ng click 则调用单独的函数 例如上传等 如何确保 ng click 不会意外提交表单 谢谢你 ngClick does not提交
  • 如何更改 Eclipse IDE 的启动 JVM?

    我在 Mac 上运行 Eclipse Oxygen 1A 我可以在 安装详细信息 中看到 IDE 本身当前使用的 JVM 实际启动 JVM 是 Oracle 的1 8 0 131JVM 我安装了一些其他 JVM 包括最新版本1 8 0 16
  • 用于电子邮件检测的 Java RegEx

    有人可以告诉我为什么以下正则表达式没有拾取以下字符串 bob at gmail dot com 吗 a zA Z0 9 s at at s w s dot dt s w 1 3 改变这个 at at to at at and dot dt
  • 使用 matplotlib 检测图像中的鼠标事件

    所以我正在尝试编写一个程序来检测图像上的鼠标单击并保存 x y 位置 我一直在使用 matplotlib 并且它可以处理基本绘图 但是当我尝试对图像使用相同的代码时 出现以下错误 cid implot canvas mpl connect
  • 无法将“WITH XMLNAMESPACES...FOR XML PATH”的输出设置为变量?

    我有一个如下查询 WITH XMLNAMESPACES DEFAULT http www somewhere com SELECT SOMETHING FOR XML PATH RootNode TYPE 运行这个效果很好 但是 当我尝试将
  • gulp-ruby-sass 在 Windows 中不是一个可识别的命令

    我第一次在 Windows Server 2012 VM 上尝试 gulp 我通常是 Mac 用户 所以我对 Windows 和 Powershell 这样的开发工具有点陌生 我安装了 Node js 和 npm 没有其他任何东西 我创建了
  • 在 Windows 命令提示符中运行最后执行的命令

    当使用 UNIX 时 我习惯于输入 运行最后执行的命令 如何在 Windows 命令提示符下执行类似的操作 followed by Enter
  • Pyaudio、portaudio 和 mac 10.7.5

    我在正确安装 pyaudio 时遇到问题 我为该项目设置了一个 virtualenv 我首先尝试安装 portaudio sudo port install portaudio 返回 gt Cleaning portaudio gt Sca
  • OpenCV 构建中的可选库提供什么?

    我正在尝试从源代码 最新的 SVN 主干 构建 OpenCV 并且有几个 可选 依赖项 它们本身的下载量将达到数 GB 尤其是使用 Qt 框架时 例如 CUDA 幽灵脚本 MIKTEX PYTHON EIGEN IPP JASPER JPE
  • 在没有 OpenMP 的计算机上忽略它

    我有一个使用 OpenMP 的 C 程序 该程序将在可能安装或未安装 OpenMP 的多台计算机上运行 我怎样才能让我的程序知道机器是否没有 OpenMP 并忽略它们 include
  • 从堆栈跟踪行号获取实际的 jsp 行号?

    这是堆栈跟踪 org apache jsp showcustomer jsp jspService showcustomer jsp java 128 org apache jasper runtime HttpJspBase servic
  • HTML5 CSS:行和调整大小

    下面的代码是响应式的 可以调整大小等 但我正在寻找一些真正简单的 CSS 来在桌面和移动设备上调整大小 我知道我可以使用标题链接 w3 css 中的 CSS 但必须有一种更好的方法来轻松地在桌面和移动设备上显示某些内容 移动设备默认显示内联
  • 打印/另存为 PDF(保留 CSS 布局)

    当我简单地打印 如在纸上 或将页面另存为 PDF 使用浏览器内置工具 时 CSS 会被完全忽略 我只会看到一行又一行的内容 有没有办法做到这一点 无需转换 HTML 2 PDF 图像 Thanks 这可能是因为你有media指定的选项
  • 当 SSM 代理变为活动状态时捕获事件

    我想在 SSM 的 Fleet Manager 中注册新的 EC2 实例时触发 lambda 这意味着可以使用 SSM 连接到该实例 但是我找不到在 EventBridge 中使用的模式 在 EventBridge 中 我尝试使用在文档中找
  • 在 SQL Server 2005 上违反 INSERT WHERE COUNT(*) = 0 上的 UNIQUE KEY 约束

    我正在从多个进程插入 SQL 数据库 这些进程有时可能会尝试将重复数据插入表中 我尝试以处理重复项的方式编写查询 但我仍然得到 System Data SqlClient SqlException Violation of UNIQUE K