所以我目前有一个主要的postgres数据库,可以处理来自不同应用程序的多个用户。因此,关于并发性的一个问题是,当AppOne和AppTwo同时想要添加用户时。
目前正在发生的事情是AppOne将生成一个随机数(必须是10位数),然后检查数据库中是否存在该值,如果它不存在则会在列中插入具有该值的用户叫user_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
的触发器运行。我可能错了。
任何帮助/建议都会有所帮助
编辑:我想要它,以便数字没有序列。这样人们就无法猜到下一个用户的网址。
由于
答案 0 :(得分:2)
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过程不允许在过程中进行多个事务。可能可以通过使用异常来解决,但它会相当复杂。
答案 1 :(得分:0)
为什么不使用UUID-ossp扩展名?它允许你从postgres本身生成UUID。
Heres a good tutorial如何将这些作为主键使用。