DB2

时间:2016-01-07 10:32:46

标签: java concurrency db2 db2-luw

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

我们的第一个天真的解决方案就是选择查看文章是否存在,以及是否我们不想插入。但是由于我们没有锁定行,所以我们遇到两个服务器同时执行select的问题,什么都没找到,然后尝试插入。当然其中一个给了我们一个重复的关键例外。

所以我们查看了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语句是原子的,两个merge语句也可以同时运行并同时选择。

有没有办法,没有锁定整个表格,以确保我们只获得一个插入?

2 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:0)

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

查尔斯