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



问题是:每天我们都会收到很多想要添加到库存中的零件。我们通过从中读取的队列(使用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);

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

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

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

我们的测试套件运行时最多有1000个同时连接,我们认为并发性不会受到仅用于该特定语句的RR隔离的太大影响。

先插入,如果抛出,则捕获重复键异常;然后改为更新。

Charles

最新更新