Postgresql 防止无序插入Postgres数据库

Postgresql 防止无序插入Postgres数据库,postgresql,Postgresql,我有一个系统,通过网络获取信息,并将这些信息放入postgres数据库。只有一种信息,所以只有一张表。让我们对这个表进行如下建模: item: string comment: jsonb timestamp: datetime Message 1: {time: 1, item: "A" } Message 2: {time: 3, item: "A" } Message 3: {time: 2, item: "b" } 有很多项,时间戳是由一个单独的系统在到达web前端之前生成的,web前

我有一个系统,通过网络获取信息,并将这些信息放入postgres数据库。只有一种信息,所以只有一张表。让我们对这个表进行如下建模:

item: string
comment: jsonb
timestamp: datetime
Message 1:
{time: 1,
item: "A"
}
Message 2:
{time: 3,
item: "A"
}
Message 3:
{time: 2,
item: "b"
}
有很多项,时间戳是由一个单独的系统在到达web前端之前生成的,web前端有几个服务器。我需要做的是确保为给定项值插入数据库的每个记录都比上一条记录更新。如果较旧,则不应将其添加到数据库中

为了澄清,假设有三条信息,如下所示:

item: string
comment: jsonb
timestamp: datetime
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文档,但看起来我无法通过约束或排除来实现这一点。如何让数据库在插入记录之前进行此排序检查?

假设您的表如下所示

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

为便于理解,在条目上创建一个复合索引将有助于更好地执行此操作。

为了理解:如果两个条目A、B按顺序A-B加上时间戳,则按顺序B-A到达插入代码时,B将被删除,而按顺序A-B到达时,它将被保留?@collapsar wait,no.如果它们按顺序B-A到达,将不会将插入到数据库中。如果它们以A-B的顺序到达,它们都将被放入数据库。让我们看看是否可以澄清这一点。您想在且仅在没有关于该项目的更长时间的消息时插入吗?@Schwern这是正确的。您能用确切的技术术语解释一下“到达”是什么意思吗?在这一过程中,他们究竟会在什么时候被视为到达目的地。您知道您的决定会对您希望从提到的几个服务器中受益的任何并发性产生什么影响吗