Aba*_*cus 6 sql-server primary-key transaction
我收到了一个我认为不可能的错误。我有一个 SQL Server(11.0.6594 版)表,如下所示:
CREATE TABLE [IDMaster](
[ID] [int] NOT NULL,
CONSTRAINT [PK_IDMaster] PRIMARY KEY CLUSTERED
([ID] ASC) ON [PRIMARY]
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
它基本上应该做 IDENTITY 现在所做的事情(已经有一段时间了)——它用于获取新的唯一整数值,这些值在其他几个表中使用。
现在我有一个 SQL 语句,它选择 MAX 值,添加到它,然后将该值插入到同一个表中——所有这些都在一个语句中。所以从理论上讲,这个语句不可能违反 PK(尽管我认为可能会陷入僵局)。但是,不知何故,它是越来越之一。
违反 PRIMARY KEY 约束“PK_IDMaster”。无法在对象“IDMaster”中插入重复键。重复的键值为 (25309587)。
我不知道这怎么可能,但显然是这样;因为它刚刚发生。
想象一下,尝试从同一张表中生成新 ID 值的任何其他方法的疯狂、奇怪的混合,它们可能与此系统中存在的内容相去甚远。但是我想不出它们会导致该特定错误的任何方式。这是我的理解是SQL Server所使用的交易锁定强制执行,不具有(NOLOCK)一个SQL语句,它或任何东西内,也不能与行,它是引用的任何干扰。
唯一的另一个因素,我认为可能不相关但谁知道,是该 SQL 包含在 TRY 中,并设置了一些选项。这是出现该错误的 SQL:
SET XACT_ABORT ON;
SET IMPLICIT_TRANSACTIONS ON;
BEGIN TRY
INSERT INTO IDMaster (ID)
SELECT COALESCE(
-- make sure the new value is odd
CASE WHEN MAX(COALESCE(ID,0)) % 2 = 0
THEN MAX(COALESCE(ID,0)) + 1
ELSE MAX(COALESCE(ID,0)) + 2
END,1)
FROM IDMaster;
END TRY
BEGIN CATCH
WHILE (@@TRANCOUNT > 0) ROLLBACK;
THROW;
END CATCH
WHILE (@@TRANCOUNT > 0) COMMIT;
Run Code Online (Sandbox Code Playgroud)
请解释:
Sea*_*ser 23
现在我有一个 SQL 语句,它选择 MAX 值,添加到它,然后将该值插入到同一个表中——所有这些都在一个语句中。所以从理论上讲,这个语句不可能违反 PK(尽管我认为可能会陷入僵局)。但是,不知何故,它正在得到一个。
这绝对是可能的。这是由于您的隔离级别以及锁定的工作方式造成的。
违反 PRIMARY KEY 约束“PK_IDMaster”。无法在对象“IDMaster”中插入重复键。重复的键值为 (25309587)。
这是由于锁定;最初在读提交隔离级别将在(在这种情况下)键上获取共享锁,同时读取最大值是什么。弄清楚之后,需要一个X锁才能插入表中。这就是它的简单概述。
当您只有一个会话时,这不是问题。当您有多个会话时,这是一个巨大的问题,因为共享锁彼此兼容。这意味着多个读取器可以获得相同的值。
不知道这怎么可能,但显然是这样;因为它刚刚发生。
看上面。
不要试图比 SQL Server 更聪明。使用适合需要的可用构造 - 在 SQL Server 2012(主要版本 11)中具有标识和序列。使用它们。
通过使用可序列化或锁定提示(如 XLOCK)故意终止并发。这会故意阻止其他会话,这意味着您的性能会降低……而您是故意这样做的……所以这看起来很糟糕,但这是一个可能的解决方案。
预先创建值(再次尝试比 SQL Server 更智能)并使用 XLOCK + READPAST 从不同的表中获得更好的并发性。废话。让我重申 #1,不要试图比 SQL Server 更聪明 [在这种情况下]。
你的理论是错误的。从您的“身份”表中读取不会锁定它,插入它会锁定它。虽然它们是单个复合语句的一部分,但它们仍然是单独的操作。在读取和插入之间的时间内,两个(或更多)连接可以从表中读取。插入使用锁,因此实际上只有一个连接能够将它们读取的值写入表中,其他连接将如您发现的那样获得主键冲突错误。
最好的解决方案是使用其中一种内置方法来处理此问题:标识列、序列或 guid。通常应该避免使用自己的解决方案:您根本没有数据库管理系统所做的经验或用户群(并且您正在处理抽象,因此即使您是主要数据库之一的程序员之一管理系统,您将无法做同样的事情)。
| 归档时间: |
|
| 查看次数: |
3053 次 |
| 最近记录: |