首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用'IF EXISTS... UPDATE .. ELSE .. INSERT‘的危险,还有什么替代方法?

使用'IF EXISTS... UPDATE .. ELSE .. INSERT‘的危险,还有什么替代方法?
EN

Stack Overflow用户
提问于 2013-06-11 16:47:10
回答 4查看 2.2K关注 0票数 0

这个问题与Occasionally Getting SqlException: Timeout expired相关。实际上,我在我的应用程序中大量使用IF EXISTS... UPDATE .. ELSE .. INSERT。但是用户Remus Rusanu说你不应该使用这个。为什么我不应该使用它,以及它包含了什么危险。所以,如果我有

代码语言:javascript
复制
IF EXISTS (SELECT * FROM Table1 WHERE Column1='SomeValue')
    UPDATE Table1 SET (...) WHERE Column1='SomeValue'
ELSE
    INSERT INTO Table1 VALUES (...)

如何重写这条语句以使其正常工作?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-06-11 16:50:23

使用MERGE

您的SQL会失败,因为在INSERT发生之前,2个并发的重叠调用和非常接近的调用都会从EXISTS得到"false“。所以他们都试图插入,当然其中一个失败了。

这里对此进行了更多的解释:Select / Insert version of an Upsert: is there a design pattern for high concurrency? This answer是旧的,并且在添加MERGE之前适用

票数 3
EN

Stack Overflow用户

发布于 2013-06-11 16:53:23

IF EXISTS ... UPDATE ... (和IF NOT EXISTS ... INSERT ...)的问题是,在并发的情况下,多个线程(事务)将执行IF EXISTS部分,并且所有线程都会得出相同的结论(例如。它不存在),并尝试相应地采取行动。结果是所有线程都尝试插入,从而导致键冲突。根据代码的不同,这可能会导致违反约束的错误、死锁、超时或更糟的情况(丢失更新)。

您需要确保检查IF EXISTS和操作是原子的。在SQL Server2008之前的版本中,该解决方案涉及到使用事务和锁提示,并且非常容易出错(很容易出错)。在SQL Server2008之后,您可以使用MERGE,它将确保正确的原子性,就像单个语句一样,并且引擎可以理解您要做的事情。

票数 2
EN

Stack Overflow用户

发布于 2013-06-11 16:57:39

Merge是为比较两个表而创建的第一个用例,因此如果是这样的话,您可以使用merge。

看看以下内容,这也是另一种选择。

不幸的是,在这种情况下,您有可能遇到并发问题。

代码语言:javascript
复制
--Just update a row 
UPDATE Table1 SET (...) WHERE Column1='SomeValue'
   -- If 0 rows are updated ...
  IF @@ROWCOUNT=0
--Insert Row
INSERT INTO Table1 VALUES (...)

this的博客中有更多的解释。

此外,this interesting blog是关于并发性的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17039925

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档