手动生成具有并发访问权限的PostgreSQL表ID

时间:2014-11-12 14:42:33

标签: postgresql

INSERT INTO rehus.curriculumsfile (fileid, originalfilename, filename, path, curriculumid, userid, companyid) VALUES ((SELECT COALESCE(MAX(fileid), 0) + 1 FROM rehus.curriculumsfile WHERE curriculumid = $1 AND userid = $2 AND companyid = $3), $4, $5, $6, $1, $2, $3)

我正在尝试在上传结束时插入数据库文件记录。但我收到重复的密钥错误,因为select在多个并发访问中生成相同的ID。我该如何解决这个问题?为什么会发生这种情况?它是相同的查询,insert和select语句都应该在相同的“db status”下解析。

我知道序列或系列应该解决问题,但它们并不适合我。

1 个答案:

答案 0 :(得分:0)

你必须忘记手动,关于并发,你不能同时拥有这两者。由你决定哪一个对你更重要。

如果您选择中断concurrency,那么您可以在事务开始时lock the table,然后插入数据并最终提交(这将释放锁定)。然后将连续处理下一个交易,依此类推。

BEGIN;

LOCK TABLE rehus.curriculumsfile;

INSERT INTO rehus.curriculumsfile ... ;

...

COMMIT;

如果您选择不生成这些ID manually,那么您可以依靠序列为您完成工作,然后如果您希望使用window function向用户显示连续的数字。< / p>

CREATE SEQUENCE curriculumsfile_fileid_seq;

ALTER TABLE
  rehus.curriculumsfile
ALTER COLUMN
  fileid
SET DEFAULT
  NEXTVAL('curriculumsfile_fileid_seq');

然后使用COALESCE(MAX(fileid)+1, 0)替换查询中的default

最后,当您查询数据时,请使用row_number()动态构建编号。

SELECT
  ROW_NUMBER() OVER (ORDER BY fileid) AS beautiful_fileid,
  ...
FROM
  rehus.curriculumsfile;

或者如果您想要实现复合编号(例如userid),那么您可以按它进行分区。

ROW_NUMBER() OVER (PARTITION BY userid ORDER BY fileid) AS beautiful_fileid