java - DB2 中合并语句的重复键异常

标签 java concurrency db2 db2-luw

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

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

所以我们转而查看合并语句。我们制作了一个看起来像这样的合并语句(为清楚起见进行了简化):

    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);

但是,出于某种原因,我们仍然遇到重复键问题。我相信即使合并语句是原子的,两个合并语句也可以并发运行并同时选择。

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

最佳答案

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

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

关于java - DB2 中合并语句的重复键异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34652886/

相关文章:

DB2 访问非唯一表中的特定行以进行更新/删除操作

java - Tomcat 8 中 DB2 的 Log4j jdbc appender

java - tomcat启动时,通常只允许每个套接字地址(协议(protocol)/网络地址/端口)使用一次?

java - JasperReports 中的软连字符支持

java - 轻松覆盖 Java 内置类的 toString()

java - 如何在并行线程中执行 observable

php - pfsockopen 线程安全?

android - AsyncTask 是否存在并发错误?

java - 适用于 DB2、Oracle 和 MSSql 的 Hibernate 序列生成策略是什么

java - 使用Java计算Google存储桶中的文件行数