这个查询在SQL Server中是安全的吗?

时间:2010-04-14 22:52:59

标签: sql sql-server tsql

我有这个SQL更新查询:

UPDATE table1 
SET table1.field1 = 1 
WHERE table1.id NOT IN (SELECT table2.table1id FROM table2);

应用程序的其他部分可以向table2添加记录,使用字段table1id引用table1。

这里的目标是从table1中删除未被table2引用的记录。

SQL Server是否会使用此类查询自动锁定table2,以便在执行此查询时无法将新记录添加到table2?

我也考虑过:

UPDATE table1 
SET field1 = 1 
WHERE 0 = (SELECT COUNT(*) FROM table2 WHERE table1.id = table2.table1id);

这似乎更安全,但速度要慢得多(因为在table1的每一行上都会调用SELECT,而不是只为NOT IN调用一次)

2 个答案:

答案 0 :(得分:5)

不,本身并不安全。子查询将获取锁并立即释放它们,允许在table2上进行并发更新/插入/删除。此外,运行此查询的多个事务可能会尝试修改table1中的相同行,即使table2稳定,可能会相互死锁。

您的第二个查询同样不安全。

很难正确地获得这些查询。对于某些查询,您可以使用XLOCK提示,但在您的情况下,您对缺少键感兴趣,因此它无济于事。唯一100%安全的替代TABLOCKX提示,但这是一个将杀死所有并发性的大锤。

最终,你必须回到退回,并问自己操作的商业含义。

  • 在您检查了之后,有人在table2 中插入了一个新密钥? 不是在那里你寻找它,所以你的操作是正确的。如果没有,那么一个事务如何插入另一个事务只是删除?它回过头来了解你的领域模型,以决定正确的行动。
  • 更新table1时,阻止在table2中插入新密钥是什么?这与上述有何不同?
  • 您的查询未更新table1之后,有人删除了您在table2 中找到的密钥,因为密钥存在?与以前相同,这与更新完成后删除密钥有什么不同?

答案 1 :(得分:0)

不,它不会。锁将尽快释放。 table2中的记录将暂时锁定,以便您获取某个时刻的记录,并根据该时刻,您的记录将从table1中“删除”。

我认为您的目标是确保在table1之前将记录插入table2。