【发布时间】:2020-06-15 23:51:24
【问题描述】:
我有两张桌子,Order 和 Slot。每个插槽都有时间,但为简单起见,我们假设它们是整数。像这样的:
Order Slot
----- ----
order_id slot_id
earliest order_id
latest time_from
time_to
我正在努力保持earliest 和latest 更新,以便earliest = MIN(slot.time_from) 和latest = MAX(time_to)。 time_from < time_to 总是如此,但这在这里不重要。
为此,我在 Slot 上创建了 UPDATE 和 INSERT 触发器。触发器:
CREATE OR REPLACE FUNCTION keep_orders_updated() RETURNS trigger AS $trigger$
BEGIN
UPDATE "order"
SET earliest=d.earliest_min, latest=d.latest_max
FROM (SELECT MIN(time_from) as earliest_min, MAX(time_to) AS latest_max FROM "slot" WHERE order_id = NEW.order_id) AS d
WHERE order_id=NEW.order_id;
RETURN NULL;
END;
$trigger$ LANGUAGE plpgsql;
CREATE TRIGGER keep_orders_updated_trigger AFTER INSERT OR UPDATE ON "slot" FOR EACH ROW EXECUTE PROCEDURE keep_orders_updated();
它在大多数情况下都会产生正确的结果,除了以下我正在尝试修复的情况。我们从这些数据开始:
Order:
order_id | earliest | latest
----------+------------------------
1 | 10 | 20
Slots:
slot_id | order_id | time_from | latest
----------+------------------------+------------------------
1 | 1 | 10 | 12
1 | 1 | 18 | 20
并且在两个并发事务中(在我的情况下,它们使用来自 Web 服务器中连接池的不同连接运行,基本上服务于大约同时到达的两个请求):
tx1: UPDATE "slot" SET time_from=15 AND time_to=17;
tx2: UPDATE "slot" SET time_from=19 AND time_to=25;
我得到正确更新的插槽(预期),并且错误地更新了顺序。仅最新更新:
Order:
order_id | earliest | latest
----------+------------------------
1 | 10 | 25
同样,如果我将 time_from 设置为小于 10 的值,它会更新。
我想我明白为什么会发生这种情况。相关行上的每个槽更新块,允许更新同时运行。触发器只看到其事务更新的数据,而不是其他事务更新的数据。因此,它会计算 tx1 的 MIN(10, 15) 和 tx2 的 MIN(10, 19),并按相关顺序将最早设置为 10。
我的理解正确吗?如何使这样的配置正常工作?
【问题讨论】:
-
我想我通过在按订单进行更新之前选择所有用于更新的插槽来修复它 (
PERFORM slot_id FROM slot WHERE order_id=NEW.order_id FOR UPDATE)。在此之前,我尝试使用插槽的 order_id 使用咨询锁,但没有奏效。
标签: sql postgresql date concurrency database-trigger