使用PostgreSQL为插入

时间:2016-04-07 19:45:25

标签: database postgresql random concurrency triggers

所以我目前有一个主要的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的触发器运行。我可能错了。

任何帮助/建议都会有所帮助

编辑:我想要它,以便数字没有序列。这样人们就无法猜到下一个用户的网址。

由于

2 个答案:

答案 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如何将这些作为主键使用。