POSTGRESQL类外键约束
我有一张名为Order 它有一个PKid多个列,一个名为POSTGRESQL类外键约束,postgresql,Postgresql,我有一张名为Order 它有一个PKid多个列,一个名为active的bool列和一个tableid列。对于一个表ID,不能同时激活两个订单,该表ID由一个类似索引的两列唯一约束(&&active=true)确保,并且查找活动订单非常快。 问题是还有另一个表orderitems。我希望active为true,除非订单id的所有orderitems都标记为paid=true。 使用序列化事务,我认为在支付代码中,如果所有项目都已支付,则可以通过设置更新查询来实现这一点。我认为这不会一直有效。因为如
active
的bool列和一个tableid列。对于一个表ID,不能同时激活两个订单,该表ID由一个类似索引的两列唯一约束(&&active=true)确保,并且查找活动订单非常快。问题是还有另一个表orderitems。我希望active为true,除非订单id的所有orderitems都标记为paid=true。
使用序列化事务,我认为在支付代码中,如果所有项目都已支付,则可以通过设置更新查询来实现这一点。我认为这不会一直有效。因为如果它们同时运行,它们可能都会看到有未支付的项目(由于旧快照),但在提交时,它们会支付所有项目,但不会更新活动列。(不同)。
添加新项目和付款交易尝试设置active=false对于串行交易不会有问题,因为其中一个交易会失败。
我认为触发器是一个解决方案,但我不知道该怎么做。。感谢您阅读您要做的是在更新后添加一个
,或者在orderitems
上为每一行插入或删除触发器,以确定是否应更改Order.active
。你必须做一个选择。。。对于拥有这些orderitems
的Order
行上的更新
,否则您将面临触发器同时运行、相互竞争和执行无序更新的风险
假定orderitems
有一个字段order\u id
,该字段是您对order.id
的外键引用,请尝试以下类似代码(未测试,仅适用于一般示例):
CREATE OR REPLACE FUNCTION orderitems_order_active_trigger() RETURNS trigger AS $$
DECLARE
_old_active BOOLEAN;
_new_active BOOLEAN;
_order_id INTEGER;
BEGIN
IF tg_op = 'INSERT' THEN
_order_id = NEW.order_id;
ELIF tg_op = 'UPDATE' THEN
_order_id = NEW.order_id;
ELIF tg_op = 'DELETE' THEN
_order_id = OLD.order_id;
ELSE
RAISE EXCEPTION 'Unexpected trigger operation %',tg_op;
END IF;
-- Lock against concurrent trigger runs and other changes in the parent record while
-- obtaining the current value of `active`
SELECT INTO _old_active Order.active FROM Order WHERE Order.id = _order_id FOR UPDATE;
-- Now figure out whether the order should be active. We'll say that if there are
-- more than zero unpaid order items found we'll treat it as active.
_new_active = EXISTS(SELECT 1 FROM orderitems WHERE orderitems.order_id = _order_id AND orderitems.paid='f');
-- If the active state has flipped, update the order.
IF _old_active IS DISTINCT FROM _new_active THEN
UPDATE Order SET active = _new_active WHERE Order.id = _order_id;
END IF;
END;
$$ LANGUAGE 'plpgsql' VOLATILE;
CREATE TRIGGER orderitems_ensure_active_correct AFTER INSERT OR UPDATE OR DELETE
ON orderitems FOR EACH ROW EXECUTE PROCEDURE orderitems_order_active_trigger();
正确的想法…触发器函数将能够处理这个问题。orderitems是否更新为设置为paid=true?还是插页?在任何情况下都要使用表格funks:Postgres文档。。。拼写检查将funcs改为funks。哈use table funks=use trigger funcs。问题是:在没有触发器的情况下是否可以完成此操作?请添加相关的表定义,包括键和约束,好吗?这可以节省一些人在9.1中使用新的trueSERIALIZABLE
模式键入的时间…@wildplasser我想如果你总是小心翼翼地进行选择,这是可能的。。。用于在插入新订单项目时对订单进行更新。您必须执行选择。。。用于更新
,因为仍然没有谓词锁定;当另一个事务正在查看具有相同订单ID的其他OrderItem时,它无法知道新插入的订单项是否会破坏可序列化性。因此,我建议在触发器中执行此操作。在9.1中,他们说存在谓词锁定。使用更新进行测试有效,但我没有使用插入进行测试