这是一个包含字段id,id_user,order_id的表。 创建记录以查找最后一个用户数并按顺序插入以下内容时需要。 我写了一个存储过程,它将下一个订单号带给用户,但即使它没有提供唯一的订单号。
CREATE OR REPLACE FUNCTION get_next_order()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $function$
DECLARE
next_order_num bigint;
BEGIN
select order_id + 1 INTO next_order_num
from payment_out
where payment_out.id_usr = NEW.id_usr
and payment_out.order_id is not null
order by payment_out.order_id desc
limit 1;
-- if payments does't exist, return 1
NEW.order_id = coalesce(next_order_num, 1);
return NEW;
END;
$function$
CREATE TRIGGER get_next_order
BEFORE INSERT
ON payment_out
FOR EACH ROW EXECUTE
PROCEDURE get_next_order()
如何避免重复的订单号?
答案 0 :(得分:0)
为了在存在多个并发事务的情况下工作,为同一个用户插入命令,您需要锁定特定记录以使它们等待并以串行方式执行。
例如,在第一个SELECT之前,您可以:PERFORM 1 FROM "users" where id_user = NEW.id_user FOR UPDATE;
您锁定拥有订单的父“用户”记录。
否则,多个并发事务可以同时执行您的过程,但是他们无法看到彼此的插入值,因此他们将选择相同的数字。
但是,请注意:当您插入依赖于它的表时,外键约束将导致SHARE
条目已经被users
锁定。您的触发器会尝试将其升级为UPDATE
锁定,但多个事务可能已经锁定SHARE
,因此会阻止。你将找到所有等待彼此的事务,直到PostgreSQL在死锁中止错误中杀死其中一个而不是其中一个。避免这种情况的唯一方法是应用程序到<{1}} 之前它会为该用户创建订单。
变体是在SELECT 1 FROM users WHERE id_user = blahblah FOR UPDATE
中保留next_order_id
字段并执行users
,并使用其结果来设置订单ID。同样的锁定升级问题也适用。