所以我目前有一个主要的 postgres 数据库,可以处理来自不同应用程序的多个用户。因此,有关并发性的问题之一是,当 AppOne 和 AppTwo 想要同时添加用户时。
目前发生的情况是 AppOne 将生成一个随机数(长度必须为 10 位),然后检查该值是否存在于数据库中,如果不存在则将具有该值的用户插入到列中称为 user_url
(用于他们的 url)。
现在,正如您可以想象的那样,如果在生成、检查或插入期间 AppTwo 发出添加用户的请求,我们可以拥有重复的唯一值(这已经发生了)。我想使用 postgres 触发器来解决这个问题。
我知道我可以使用事务,但我不想阻止数据库,我宁愿它通过数据库端的函数和触发器创建唯一的数字序列,所以当我扩展时我不会不必担心竞争条件。一旦触发器执行了操作,我就可以获取新添加的用户及其所有数据,包括唯一的 ID。
非常理想
CREATE OR REPLACE FUNCTION set_unique_number(...) RETURNS trigger AS $$
DECLARE
BEGIN
....something here
RETURN new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER insert_unique_url_id BEFORE INSERT ... PROCEDURE
set_unique_number(...);
它将是一个生成数字并将其插入到行中的函数,该函数将由 BEFORE INSERT
触发器运行。我可能是错的。
任何帮助/建议都会有帮助
编辑:我希望数字没有顺序。这样人们就无法猜测下一个用户的网址。
谢谢
最佳答案
9,000,000,000 是一个足够小的数字,生日问题将保证您很快就会开始看到冲突。
我认为您可以解决这个问题,同时仍然允许使用advisory locking并发插入。您的过程可能如下所示(伪代码):
while (true) {
start transaction;
bigint new_id = floor(random())*9000000000+1000000000;
if select pg_try_advisory_xact_lock(new_id) {
if select not exists id from url where id=new_id {
insert into url (id, ...) values (new_id, ...);
commit;
break;
}
}
commit;
}
当数据库中有 9,000,000,000 行时,此过程将永远不会结束。您必须在外部实现它,因为 Postgres 过程不允许在一个过程中进行多个事务。或许可以通过使用异常来解决,但会相当复杂。
关于database - 使用 PostgreSQL 在插入时为行生成唯一 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36485778/