这个问题与Occasionally Getting SqlException: Timeout expired相关。实际上,我在我的应用程序中大量使用IF EXISTS... UPDATE .. ELSE .. INSERT。但是用户Remus Rusanu说你不应该使用这个。为什么我不应该使用它,以及它包含了什么危险。所以,如果我有
IF EXISTS (SELECT * FROM Table1 WHERE Column1='SomeValue')
UPDATE Table1 SET (...) WHERE Column1='SomeValue'
ELSE
INSERT INTO Table1 VALUES (...)如何重写这条语句以使其正常工作?
发布于 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之前适用
发布于 2013-06-11 16:53:23
IF EXISTS ... UPDATE ... (和IF NOT EXISTS ... INSERT ...)的问题是,在并发的情况下,多个线程(事务)将执行IF EXISTS部分,并且所有线程都会得出相同的结论(例如。它不存在),并尝试相应地采取行动。结果是所有线程都尝试插入,从而导致键冲突。根据代码的不同,这可能会导致违反约束的错误、死锁、超时或更糟的情况(丢失更新)。
您需要确保检查IF EXISTS和操作是原子的。在SQL Server2008之前的版本中,该解决方案涉及到使用事务和锁提示,并且非常容易出错(很容易出错)。在SQL Server2008之后,您可以使用MERGE,它将确保正确的原子性,就像单个语句一样,并且引擎可以理解您要做的事情。
发布于 2013-06-11 16:57:39
Merge是为比较两个表而创建的第一个用例,因此如果是这样的话,您可以使用merge。
看看以下内容,这也是另一种选择。
不幸的是,在这种情况下,您有可能遇到并发问题。
--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是关于并发性的。
https://stackoverflow.com/questions/17039925
复制相似问题