问题:我们每天都会收到许多我们想要添加到库存中的零件。我们通过我们读取的队列(使用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语句也可以同时运行并同时选择。
有没有办法,没有锁定整个表格,以确保我们只获得一个插入?
答案 0 :(得分:3)
在类似情况下,使用可重复读取隔离级别运行MERGE
解决了我们的问题。 RS是不够的,因为它仍然允许幻像行,这正是您遇到的问题。您只需在语句末尾添加WITH RR
即可试用。
我们的测试套件最多可同时运行1000个连接,并且我们看不到并发性受到仅用于该特定语句的RR隔离的影响很大。
答案 1 :(得分:0)
首先执行插入操作,如果抛出则捕获重复键异常;然后更新。
查尔斯