如果事务同时发生,则此存储过程通常会失败,因为它违反了重复键(字段,名称)上的pk约束。我一直在尝试, holdlock, rowlock和begin / commit transaction,这会导致同样的错误。
我正在尝试执行insert语句,如果记录中存在相同的键(字段,名称),请更新它。
性能很重要,所以我试图避免临时表解决方案。
MERGE Fielddata AS TARGET
USING (VALUES (@Field, @Name, @Value, @File, @Type))
AS SOURCE (Field, Name, Value, File, Type)
ON TARGET.Field = @Field AND TARGET.Name = @Name
WHEN MATCHED THEN
UPDATE
SET Value = SOURCE.Value,
File = SOURCE.File,
Type = SOURCE.Type
WHEN NOT MATCHED THEN
INSERT (Field, Name, Value, File, Type)
VALUES (SOURCE.Field, SOURCE.Name, SOURCE.Value, SOURCE.File, SOURCE.Type);
编辑:使用serializable / holdlock进行24小时测试。 30分钟后:没有错误。
编辑2:WITH (SERIALIZABLE)
/ SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
有效地解决了重复的关键问题,在我们的案例/场景中花费了一点点性能。
答案 0 :(得分:2)
您必须提高事务隔离级别。 设置交易隔离级别可串行化
SERIALIZABLE指定以下内容:+语句无法读取数据 已被修改但尚未由其他交易承诺的。没有 其他事务可以修改当前读取的数据 事务直到当前事务完成。 其他 事务无法插入具有可能落入的键值的新行 当前事务中任何语句读取的键范围 直到当前事务完成。范围锁定放在 与每个语句的搜索条件匹配的键值范围 在交易中执行。这阻止了其他交易 更新或插入任何符合任何条件的行 当前事务执行的语句。这意味着,如果有的话 它们是第二次执行事务中的语句 将读取相同的行集。范围锁保持到 交易完成。这是最严格的隔离 级别,因为它锁定整个键范围并保持锁定 直到交易完成。因为并发性较低,请使用 此选项仅在必要时使用。 此选项与效果相同 在a中所有SELECT语句中的所有表上设置HOLDLOCK 事务。强>
可序列化的实现
SQL Server碰巧使用了serializable的锁定实现 隔离级别,物理锁被获取并保持到最后 的事务(因此不推荐的表提示HOLDLOCK为 SERIALIZABLE的同义词。
这种策略还不足以提供技术保障 完全可串行化,因为新的或更改的数据可能出现在 事务先前处理的行范围。这个 并发现象被称为幻像,并且可以导致 任何连续计划中都不会发生的影响。
为了确保防止幻像并发现象,锁定 SQL Server在可序列化隔离级别上采取的也可能 合并键范围锁定以防止新行或更改行 出现在先前检查的索引键值之间。范围锁 并不总是在可序列化的隔离级别下获得;我们所有人 可以说一般来说SQL Server总是获得足够的锁 满足可序列化隔离级别的逻辑要求。 事实上,锁定实现经常获得更多,并且 比确保可串行化所需的更严格的锁定, 但我离题了。
https://sqlperformance.com/2014/04/t-sql-queries/the-serializable-isolation-level
如果简单:它不仅会阻止来源,还会阻止插入范围