PostgreSQL UUID生成

13
select uuid_generate_v4() as one, uuid_generate_v4() as two;

"one" uuid 和 "two" uuid 相等!

CREATE TABLE "TB"
(
  "Id" uuid NOT NULL DEFAULT uuid_generate_v4(),
  "Title" character varying NOT NULL,
   CONSTRAINT "TB_Class_ID" PRIMARY KEY ("Id")
);

PostgreSQL 9.0 和 pgAdmin 1.12.3。

insert into "TB" ("Id", "Title") values (uuid_generate_v4(), '111');
insert into "TB" ("Id", "Title") values (uuid_generate_v4(), '111');
insert into "TB" ("Id", "Title") values (uuid_generate_v4(), '111');

或者

insert into "TB" ("Title") values ('111');
insert into "TB" ("Title") values ('111');
insert into "TB" ("Title") values ('111');

结果:

ERROR:  duplicate key value violates unique constraint "TB_Class_ID"
DETAIL:  Key ("Id")=(12ab6634-995a-4688-9a9a-ee8c3fe24395) already exists.

相比之下

postgreSQL maestro 9.2.0.4

insert into "TB" ("Id", "Title") values (uuid_generate_v4(), '111');
insert into "TB" ("Id", "Title") values (uuid_generate_v4(), '111');
insert into "TB" ("Id", "Title") values (uuid_generate_v4(), '111');

结果:1行受影响;

我理解maestro逐个添加记录,但为什么uuid_generate_v4()在两次调用后返回相同的值?(在pgAdmin情况下)。

如何通过一个请求添加多行?


这对我来说看起来像是一个bug。尝试使用SELECT random() AS one, random() AS two;。无论我是否处于事务中,我都会得到两个不同的值。uuid_generate_v4是一个VOLATILE函数,因此我认为故障要么在uuid-ossp模块中,要么在底层库中。 - Joey Adams
1
是的,“SELECT random() AS one, random() AS two”会得到不同的值,但我不明白为什么uuid_generate_v4会得到相等的值。 - bartolo-otrit
3个回答

17

在过去的某个时刻,uuid_generate_* 函数被错误地标记为 IMMUTABLE,这将导致您所展示的行为。这已经在所有最新的小版本中得到修复,但是您必须重新运行安装脚本(uuid-ossp.sql)以获取更新的函数定义。(您还可以查看安装脚本,以验证您是否拥有最新版本。函数应该被标记为 VOLATILE。)


1
我在 uuid-ossp.sql 中用 VOLATILE 替换了 IMMUTABLEselect uuid_generate_v1() as one, uuid_generate_v4() as two会给出两个不同的结果,但是insert into "TB" ("Id", "Title") values (uuid_generate_v4(), '111'); insert into "TB" ("Id", "Title") values (uuid_generate_v4(), '111');仍然会提示 "duplicate key" 错误。 - bartolo-otrit
1
你上面展示的表定义甚至没有唯一约束条件,所以你并没有告诉我们全部的真相。 - Peter Eisentraut
抱歉,帖子已更新 CONSTRAINT "TB_Class_ID" PRIMARY KEY ("Id") - bartolo-otrit

13

在给定的事务中,函数uuid_generate_v4()返回相同的值。

当语句被分组并作为“一个命令”运行时,存在一个事务,因此每次调用uuid_generate_v4()都会返回相同的值。

“修复”这个问题的两种方法是:

  1. 每次使用该函数时进行单独的数据库调用(这是最简单的方法)
  2. 使用非自动提交连接,在其中控制事务并将每个使用分开写在一个BEGIN; COMMIT 对中(这很麻烦 - 除非必须这样做,否则不要这样做)

6
提供给所有通过谷歌或其他方式进入此处的人参考,但我认为这不再是一个错误或问题。在我的PostgreSQL 9.3 / 9.4安装中,“select uuid_generate_v4() as one, uuid_generate_v4() as two”可以正常工作。就像@peter-eisentraut所说,这可能是很久以前就已经修复的错误。 - The Alchemist

4
为避免重复,您可以使用以下方式生成代码:
select md5(random()::text || clock_timestamp()::text)::uuid AS new_id, id from table;

但要小心:这只生成 UUID 而不是 UUIDv4。更多详细信息请参见:在Postgres中生成用于插入语句的UUID?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接