防止乱序插入Postgres数据库

时间:2019-07-05 20:37:47

标签: postgresql

我有一个系统,该系统通过网络获取信息并将其存储在postgres数据库中。信息只有一种“种类”,因此只有一张表。让我们为这个表建模:

item: string
comment: jsonb
timestamp: datetime

有很多项目,时间戳是由一个单独的系统生成的,然后才到达具有数台服务器的Web前端。我需要做的是确保为给定的item值插入数据库的每个记录都比上一个更新。如果它较旧,则不应将其添加到数据库中。

为澄清起见,假设有以下三种消息:

Message 1:
{time: 1,
item: "A"
}
Message 2:
{time: 3,
item: "A"
}
Message 3:
{time: 2,
item: "b"
}

如果消息以1-2-3的顺序到达,则所有三个消息都将放入数据库中,因为消息3与消息1或2是不同的项,因此不进行比较。

如果消息以2-1-3的顺序到达,则消息1不会放置在数据库中,因为消息2是项A的更新消息。

我想使用数据库进行此检查,以避免不同服务器之间的竞争状况。

我一直在阅读PostgreSQL文档,但看起来我不能通过约束或排除来做到这一点。我如何让数据库在插入记录之前进行此排序检查?

1 个答案:

答案 0 :(得分:4)

假设您的桌子看起来像这样...

create table messages (
    item text not null,
    comment jsonb,
    created_at timestamp not null
);

您可以使用触发器来完成此操作。

create or replace function check_only_newer_messages_for_item() returns trigger as $foo$
declare max_created_at_for_item timestamp;
begin
    max_created_at_for_item := (
        select coalesce(max(created_at), '-infinity'::timestamp)
        from messages
        where item = new.item
    );
    if max_created_at_for_item >= new.created_at then
        raise exception 'out of order message';
    end if;
    return new;
end;
$foo$ language plpgsql;

create trigger only_newer_messages_for_item
    before insert on messages
    for each row execute function check_only_newer_messages_for_item();

test=# insert into messages (item, created_at) values ('a', '2019-01-01');
INSERT 0 1
test=# insert into messages (item, created_at) values ('a', '2019-01-01');
ERROR:  out of order message
CONTEXT:  PL/pgSQL function check_only_newer_messages_for_item() line 10 at RAISE
test=# insert into messages (item, created_at) values ('b', '2018-01-01');
INSERT 0 1
test=# insert into messages (item, created_at) values ('b', '2018-01-02');
INSERT 0 1
test=# insert into messages (item, created_at) values ('b', '2018-01-01');
ERROR:  out of order message
CONTEXT:  PL/pgSQL function check_only_newer_messages_for_item() line 10 at RAISE

itemcreated_at上的综合索引将有助于其良好运行。