代码之家  ›  专栏  ›  技术社区  ›  Astrogat

DB2中merge语句出现重复键异常

  •  1
  • Astrogat  · 技术社区  · 9 年前

    问题是:每天我们都会得到很多我们想添加到库存中的零件。我们从队列中读取消息(使用4个不同的服务器)。队列始终包含元素,因此服务器可以尽可能快地读取。我们希望服务器在文章退出时简单地更新文章,如果不退出则插入文章。

    我们的第一个天真的解决方案是简单地选择看看文章是否存在,如果不存在,我们想插入。然而,由于没有行可供我们锁定,我们遇到了两个服务器同时执行选择、找不到任何内容,然后尝试插入的问题。当然,其中一个给了我们一个重复的密钥例外。

    因此,我们转而查看了merge语句。我们做了一个如下的合并语句(为了清楚起见,简化了):

        MERGE INTO articles sr
        USING ( 
            VALUES (:PARAM_ARTICLE_NUMBER))
            AS v(ARTICLE_NUMBER)
        ON sr.ARTICLE_NUMBER = v.ARTICLE_NUMBER
        WHEN MATCHED THEN 
            UPDATE SET 
            QUANTITY = QUANTITY + :PARAM_QUANTITY
                    ARRIVED_DATE = CASE WHEN ARRIVED_DATE IS NULL
                    THEN :PARAM_ARRIVED_DATE
                    ELSE ARRIVED_DATE END
        WHEN NOT MATCHED THEN
            INSERT (QUANTITY, ARRIVED_DATE)
            VALUES (:PARAM_QUANTITY, CURRENT_TIMESTAMP);
    

    然而,由于某些原因,我们仍然面临着重复的关键问题。我认为,即使合并语句是原子的,两个合并语句也可以同时运行和选择。

    除了锁定整个表之外,还有什么方法可以确保我们只插入一个表吗?

    2 回复  |  直到 7 年前
        1
  •  4
  •   mustaccio Gandalf    9 年前

    在类似情况下,运行 MERGE 可重复读取隔离级别解决了我们的问题。RS是不够的,因为它仍然允许幻影行,这正是您遇到的问题。您可以简单地添加 WITH RR 在语句的末尾,尝试一下。

    我们的测试套件可以运行多达1000个同时连接,我们看不到并发性受到仅用于特定语句的RR隔离的影响。

        2
  •  0
  •   Charles    9 年前

    首先执行插入,如果抛出,则捕获重复的键异常;然后更新。

    查尔斯