1
                if exists (select 1 from schema.TableName (nolock) where Id = @id) 
                update schema.TableName set DocumentXML = @documentXml, ClientDocumentGUID=@clientDocGuid, Incomplete = @incomplete where Id = @id
                else
                insert into schema.TableName
                select @id, @templateId, @clientVisitGuid, @clientGuid, @chartGuid, @scmDocumentGuid, @clientDocGuid, @incomplete, getdate(), @createdByGuid, @documentXml

我有一个运行上述查询的 C# 程序。我遇到了行被插入两次的情况。我认为问题是这个查询。这个想法是查询可以在相同的情况下运行两次@Id。第一次应该是插入,第二次应该是更新。

请注意,查询有一个(no lock). 这是否意味着查询不一定以 FIFO 方式运行?我相信只有当我异步运行这个查询时才会出现两行问题。

4

3 回答 3

1

If you have two requests processing at the same time they will both insert since your ignoring all locks on the first table. I like using merge in these cases. Or remove your no lock and ensure your transaction isolation level is snapshot or serialized.

于 2012-10-10T20:53:26.973 回答
0

根据事务隔离级别查询可以并行运行......

于 2012-10-10T20:38:48.097 回答
0

使用 NOLOCK 提示会导致 SQL Server 忽略所有锁。这意味着一个查询可能最终会读取它们中间的值被更改,这会导致返回完全垃圾。

但是,删除 NOLOCK 提示是不够的。您需要确保所有语句都在调用应用程序或过程中的事务中执行。如果您使用程序,请先查看以下内容:如何在程序中回滚

将语句包装在事务中后,您还需要确保 IF EXISTS 语句对行进行更新或排他锁,以防止其他人在您的语句之间插入行,因此您需要 UPDLOCK 或 XLOCK暗示。由于该行可能还不存在,这也只能在可序列化事务隔离级别中实现。

在你实现了所有这些之后,你仍然在浪费这个设置的读取。这可能会在以后成为性能问题。

--

长话短说:正如 JoshBerke 建议的那样,在这种情况下,您应该真正使用 MERGE 语句。这将在更快、更容易维护的同时防止您的问题。但是,它需要 2008 或更高版本。有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/bb510625.aspx

于 2012-10-11T02:41:14.870 回答