SQL Server锁-避免插入重复条目
在阅读了大量与上述主题相关的文章和答案后,我仍然想知道SQL Server数据库引擎在以下示例中是如何工作的: 假设我们有一个名为t3的表:SQL Server锁-避免插入重复条目,sql,sql-server,Sql,Sql Server,在阅读了大量与上述主题相关的文章和答案后,我仍然想知道SQL Server数据库引擎在以下示例中是如何工作的: 假设我们有一个名为t3的表: create table t3 (a int , b int); create index test on t3 (a); 以及以下查询: INSERT INTO T3 SELECT -86,-86 WHERE NOT EXISTS (SELECT 1 FROM t3 where t3.a=-86); 在基于列“a”验证行不存在后,查询在表t3中插入一
create table t3 (a int , b int);
create index test on t3 (a);
以及以下查询:
INSERT INTO T3
SELECT -86,-86
WHERE NOT EXISTS (SELECT 1 FROM t3 where t3.a=-86);
在基于列“a”验证行不存在后,查询在表t3中插入一行
许多文章和答案表明,使用上述查询不可能将一行插入两次
为了执行上述查询,我假设数据库引擎的工作方式如下:
INSERT INTO T3
SELECT -86,-86
WHERE NOT EXISTS (SELECT 1 FROM t3 where t3.a=-86);
现在考虑下面的场景:
begin tran
if (SELECT 1 FROM t3 with (updlock) where t3.a=-86)
begin
INSERT INTO T3
SELECT -86,-86
end
commit
如果列上只有一个唯一的约束,则永远不会有重复的约束 您概述的技术将避免在(第二次“同时”)操作失败的情况下捕获错误或异常
我想补充一点,依靠“外部”代码(甚至T-SQL)来增强数据库的一致性不是一个好主意。在所有情况下,在表级别使用声明性引用完整性对于数据库确保一致性和匹配期望都很重要,无论应用程序代码编写得是否良好。与安全性一样,您需要利用深度防御策略—约束、唯一索引、触发器、存储过程和视图都有助于采取多层方法,以确保数据库为应用程序或系统提供一致和可靠的接口。要在多条语句之间保持锁定,它们必须包装在事务中。在您的示例中:
If (SELECT 1 FROM t3 with (updlock) where t3.a=-86)
INSERT INTO T3 SELECT -86,-86
可以在执行插入之前释放更新锁。这将可靠地工作:
begin transaction
If (SELECT 1 FROM t3 with (updlock) where t3.a=-86)
INSERT INTO T3 SELECT -86,-86
commit transaction
单个语句始终包装在事务中,因此这也会起作用:
INSERT INTO T3 SELECT -86,-86
WHERE NOT EXISTS (SELECT 1 FROM t3 with (updlock) where t3.a=-86)
(这是假设您关闭了“隐式事务”,如默认的SQL Server设置。)是的,唯一的约束/索引是首选的,也是唯一可靠的防止重复的方法。在某些情况下,其他任何事情都注定要失败。这是正确的。这两个语句必须包含在一个事务中。我更正了问题中的陈述。那么你是说插入到。。。如果不强制执行更新锁,则(…)语法将不起作用。这就是我所知道的,但在读了这么多文章,甚至没有提到这一点之后,我开始怀疑它是否真的需要。谢谢你的澄清。