DB2 中合并语句的重复键异常
Duplicate key exception on merge statement in DB2
问题:每天我们都会收到很多想要添加到库存中的零件。我们通过从中读取的队列获取消息(使用 4 个不同的服务器)。队列始终包含元素,以便服务器尽可能快地读取。我们希望服务器在文章退出时简单地更新文章,如果不存在则插入它。
我们第一个天真的解决方案是 select 查看文章是否存在,如果不存在我们就想插入。然而,由于没有行供我们锁定,我们遇到了两台服务器同时执行 select 的问题,找不到任何内容,然后尝试插入。当然其中之一给了我们一个重复键异常。
所以我们转而查看合并语句。我们做了一个看起来像这样的合并语句(为清楚起见进行了简化):
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);
但是,由于某些原因,我们仍然遇到重复键问题。我相信即使合并语句是原子的,两个合并语句也可以 运行 并发 select 同时。
除了锁定整个 table 之外,还有什么方法可以确保我们只插入一个?
先做insert,抛出duplicate key异常时捕获;然后更新。
查尔斯
在类似的情况下 运行 具有可重复读取隔离级别的 MERGE
解决了我们的问题。 RS 不够,因为它仍然允许幻像行,这正是您遇到的问题。您可以简单地在语句末尾添加 WITH RR
并尝试一下。
我们的测试套件运行最多 1000 个并发连接,我们没有看到并发性受到仅用于该特定语句的 RR 隔离的太大影响。
问题:每天我们都会收到很多想要添加到库存中的零件。我们通过从中读取的队列获取消息(使用 4 个不同的服务器)。队列始终包含元素,以便服务器尽可能快地读取。我们希望服务器在文章退出时简单地更新文章,如果不存在则插入它。
我们第一个天真的解决方案是 select 查看文章是否存在,如果不存在我们就想插入。然而,由于没有行供我们锁定,我们遇到了两台服务器同时执行 select 的问题,找不到任何内容,然后尝试插入。当然其中之一给了我们一个重复键异常。
所以我们转而查看合并语句。我们做了一个看起来像这样的合并语句(为清楚起见进行了简化):
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);
但是,由于某些原因,我们仍然遇到重复键问题。我相信即使合并语句是原子的,两个合并语句也可以 运行 并发 select 同时。
除了锁定整个 table 之外,还有什么方法可以确保我们只插入一个?
先做insert,抛出duplicate key异常时捕获;然后更新。
查尔斯
在类似的情况下 运行 具有可重复读取隔离级别的 MERGE
解决了我们的问题。 RS 不够,因为它仍然允许幻像行,这正是您遇到的问题。您可以简单地在语句末尾添加 WITH RR
并尝试一下。
我们的测试套件运行最多 1000 个并发连接,我们没有看到并发性受到仅用于该特定语句的 RR 隔离的太大影响。