Sql server 由于更新冲突,快照隔离事务中止

Sql server 由于更新冲突,快照隔离事务中止,sql-server,tsql,transactions,transaction-isolation,snapshot-isolation,Sql Server,Tsql,Transactions,Transaction Isolation,Snapshot Isolation,以下声明: INSERT INTO dbo.Changes([Content], [Date], [UserId], [CompanyId]) VALUES (@1, @2, @3, @4); SELECT @@identity; 给我这个SQL错误3960: 由于更新冲突,快照隔离事务中止。你 无法使用快照隔离直接访问表“dbo.companys” 或间接在数据库“myDatabase”中进行更新、删除或插入 已被其他事务修改或删除的行。 重试事务或更改事务的隔离级别 更新/删除语句

以下声明:

INSERT INTO dbo.Changes([Content], [Date], [UserId], [CompanyId]) 
  VALUES (@1, @2, @3, @4);
SELECT @@identity;
给我这个SQL错误3960:

由于更新冲突,快照隔离事务中止。你 无法使用快照隔离直接访问表“dbo.companys” 或间接在数据库“myDatabase”中进行更新、删除或插入 已被其他事务修改或删除的行。 重试事务或更改事务的隔离级别 更新/删除语句

据我所知,从错误消息中,我不应该在另一个连接修改dbo.companys时更新、删除或插入表
dbo.companys

但为什么在我将新行插入另一个表
dbo.Changes
(该表的外键为
dbo.companys
)时会发生这种情况,并且我没有删除
dbo.companys
中的引用行,而只是更新了
dbo.companys
中的行,而不是主键?这应该行,不是吗?(这是SQL Server中的错误吗?)

更新:

表如下所示:

dbo.Changes([Id] int PK, [Content] nvarchar, 
  [Date] datetime, [UserId] int, [CompanyId] int -> dbo.Companies.[Id])
dbo.Companies([Id] int PK, [Name] nvarchar)
第二个更新是:

UPDATE dbo.Companies WHERE [Id] = @1 SET [Name] = @2;

SQL Server可以看到对依赖表的更新,该更新可能会修改插入的行为。。。对我来说似乎很公平,因为SQL无法猜测[name]列(触发器等)可能依赖于哪些其他逻辑


如果您的应用程序实现死锁重试逻辑,您可以对其进行修改,以将错误号3960与错误号1205处理相同,并自动重试…

SQL Server似乎会对其必须读取的任何记录获取更新锁,即使它没有修改它

更多信息:

在CustomerContactPerson上没有支持索引的情况下,该语句

从ContactPerson中删除,其中ID=@ID

将需要一个“当前” 读取CustomerContactPerson中的所有行,以确保 没有引用已删除列表的CustomerContactPerson行 联系人行。通过索引,DELETE可以确定 如果未读取列表,CustomerContactPerson中没有相关行 受其他事务影响的行

此外,在快照中 事务-用于读取要转换的数据的模式 当你阅读的时候,你需要做一个升级锁。这确保了 您是根据“当前”数据进行更新,而不是 “一致”(快照)数据,并且在发出DML时 数据不会被锁定,您也不会无意中覆盖另一个数据 会议的变化

我们的解决方案是向外键添加索引


在您的示例中,我怀疑向Changes.CompanyId添加索引会有所帮助。我不确定这是否是一个真正的解决方案。SQL Server优化器是否可以选择不使用索引?

谢谢您的提示,但它似乎没有帮助。这两条语句(INSERT和UPDATE)是否都指向同一客户?如果是这样的话,据我所知,我们运气不好。是的,insert使用的是当前更新公司的id。通过(长)DBAPOT线程读取,听起来这是SQL Server的一个限制。这个答案中的索引只在两个状态涉及不同客户的情况下才有帮助。谢谢,碰巧有一个包含十几个FK的表,没有人关心创建索引,在创建丢失的索引之后,到目前为止没有出现类似的错误。你说得很对。。。。除此之外,我仍然不明白为什么在相关表的外键列上有一个非聚集的、非唯一的索引就足以避免这种情况发生——也就是说,即使使用索引,它是否仍然可以修改插入的行为?@Kram我想索引有助于提高粒度。引擎知道依赖表需要锁定,但如果没有索引,它可以尝试锁定整个表,而不是一行