database - 使用 PostgreSQL 在插入时为行生成唯一 ID

标签 database postgresql random concurrency triggers

所以我目前有一个主要的 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/

相关文章:

arrays - PostgreSQL fdw 表性能在 5 次相同查询后呈指数下降

c# - 随机化字符串中的字符列表,C#

java - 为什么使用相似种子时初始随机数相似?

mysql - SELECT继承性能: LEFT OUTER JOIN vs "super-table" TYPE COLUMN

sql - 如何在表格中找到一系列没有间隙的序列号

sql - 更新表中给定年份的所有时间戳

sql - 如何让以下 SQL 查询正确选择组内的前 N ​​个结果?

php - 使用mysql从数组中洗牌

sql - 在查询中按参数匹配计数搜索排序?数据库

c++ - 使用来自远程计算机的 libpq 在 PostgreSQL 中插入二进制大对象 (BLOB)