如何绕过我的 SQL Server 约束?

lad*_*dge 8 sql-server-2008 sql-server

我们在我们的数据库中发现了一些违反活动约束的行。这怎么可能?

约束处于活动状态,因为我们不能手动添加绕过此约束的行。但是,当我们运行 时CHECKCONSTRAINTS(Files),我们发现它在我们的测试运行期间有几次被绕过了。有问题的行都是在半秒内创建的,表明存在某种竞争条件。

这是应用于表的约束。该规则旨在确保给定父文件夹中的名称唯一性:

ALTER TABLE Files ADD CONSTRAINT UniqueNameInParentFolder CHECK
    CheckUniqueNameInFolder(ParentFoldersID, Name) = 1;
Run Code Online (Sandbox Code Playgroud)

此约束调用如下所示的函数:

-- first check for the new name in the Folders table
IF ((SELECT COUNT(*) FROM Folders 
     WHERE ParentFoldersID = @FoldersID AND Name = @Name) = 0)
BEGIN 
    -- then check for it in the Files table
    IF ((SELECT COUNT(*) FROM Files 
         WHERE ParentFoldersID = @FoldersID AND Name = @Name) <= 1)
        RETURN 1
END
RETURN 0
Run Code Online (Sandbox Code Playgroud)

在事务中添加了单独的行,所以我很难理解重复的行是如何绕过这个限制的。

gbn*_*gbn 20

基于 UDF 的检查约束是垃圾。并发、RBAR、隔离等,如您所见。一些链接:

在这种情况下,SQL Server 最安全的方法是使用标准约束,例如唯一键和外键。我不明白为什么你检查文件夹表中文件表的约束。

为了防止文件和文件夹在给定的父文件夹中具有相同名称,请使用索引视图。重复文件或重复文件夹需要表级唯一性。

CREATE VIEW CheckUnique
WITH SCHEMABINDING
AS
SELECT fo.ParentFoldersID, fo.Name
FROM
   Folders fo
   JOIN
   File fi ON fo.ParentFoldersID  = fi.ParentFoldersID AND fo.Name = fi.Name
GO
CREATE UNIQUE CLUSTERED INDEX IXCU_CheckUnique ON CheckUnique (ParentFoldersID, Name)
GO
Run Code Online (Sandbox Code Playgroud)

或者触发器。

绝不是检查约束中的 UDF


Rem*_*anu 13

CheckUniqueNameInFolder 函数几乎不检查任何东西。在该约束检查下可以添加大量重复项。它具有被顺序运行,并且,在任何情况下,约束讲述,充其量(因此的条件由所述第一选择可以由第二个运行时间被无效选中),有两个不同的SELECTS没有重复检查时发生,绝不做它告诉大家,那里当插入/更新不会出现重复。由于检查不会锁定在 U 或 X 模式下验证的键,因此可以同时进行多个插入,进行检查,发现没有重复项,然后全部继续插入相同的条目。

正确实施唯一约束的唯一方法是使用唯一约束

使用“文件”的完整路径创建一个计算列,并使用 UNIQUE 约束在整个路径上强制执行唯一性,或者在 上使用 UNIQUE 约束(ParentFolderID, Name)。不要分别存储文件夹和文件,对文件夹和文件(例如条目)使用公共表,因为它们占用相同的命名空间。


Mar*_*ith 6

在默认级别的事务中运行此命令read committed将在负载下失败。

读取不是互斥和序列化的,因此两个并发事务都可以读取该行不存在。您可以UPDLOCK,ROWLOCK,HOLDLOCKSELECT.