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

use*_*erx 1 sql t-sql sql-server

我有这个SQL更新查询:

UPDATE table1 
SET table1.field1 = 1 
WHERE table1.id NOT IN (SELECT table2.table1id FROM table2);
Run Code Online (Sandbox Code Playgroud)

应用程序的其他部分可以向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);
Run Code Online (Sandbox Code Playgroud)

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

Rem*_*anu 5

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

你的第二个查询同样不安全.

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

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

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