Sequelize模型中UUIDv4生成重复键值问题求助
问题详情
我是TypeScript和Express新手,在Sequelize模型中将UUID类型的code字段设为主键,配置defaultValue: DataTypes.UUIDV4后,每次插入都会生成相同的UUID。首次插入数据成功,第二次插入时触发PostgreSQL唯一约束错误,提示键值重复。
模型代码
'use strict'; const { v4: uuidv4 } = require('uuid'); const { Model, Sequelize } = require('sequelize'); module.exports = (sequelize, DataTypes) => { class Hotel extends Model { static associate(models) { } } Hotel = sequelize.define('Hotel', { code: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true, allowNull: false, }, name: { type: DataTypes.STRING(256), allowNull: false, } }, { sequelize, tableName: 'hotel_hotel', schema: 'public', timestamps: false, }); return Hotel; };
PostgreSQL建表语句
BEGIN; CREATE TABLE IF NOT EXISTS public.hotel_hotel ( code uuid NOT NULL, "name" character varying(256) NOT NULL, PRIMARY KEY(code) ); COMMIT;
执行日志
首次插入日志:
Executing (default): INSERT INTO "public"."hotel_hotel" ("code","name") VALUES ($1,$2) RETURNING "code","name";
第二次插入错误日志:
Executing (default): INSERT INTO "public"."hotel_hotel" ("code","name") VALUES ($1,$2) RETURNING "code","name";
2022-12-21 07:58:04.561 UTC [65] ERROR: duplicate key value violates unique constraint "hotel_hotel_pkey"
2022-12-21 07:58:04.561 UTC [65] DETAIL: Key (code)=(a66eef94-d28e-4dc7-81f7-6346d2c255f3) already exists.
解决方案
问题核心是DataTypes.UUIDV4未被识别为动态生成函数,被当作固定值重复使用。以下两种方案可解决:
方案一:使用uuid库动态生成UUID
直接利用已引入的uuid库,通过函数返回新UUID:
修改模型中code字段的defaultValue配置:
code: { type: DataTypes.UUID, defaultValue: () => uuidv4(), // 用箭头函数每次调用生成新UUID primaryKey: true, allowNull: false, }
方案二:让PostgreSQL自动生成UUID
将UUID生成逻辑移至数据库端,更适合多服务操作同一数据库的场景:
- 先确保PostgreSQL安装
uuid-ossp扩展(未安装则执行):
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
- 修改建表语句,给
code字段添加数据库默认值:
BEGIN; CREATE TABLE IF NOT EXISTS public.hotel_hotel ( code uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying(256) NOT NULL, PRIMARY KEY(code) ); COMMIT;
- 同步修改Sequelize模型配置,让数据库负责生成UUID:
code: { type: DataTypes.UUID, defaultValue: Sequelize.literal('uuid_generate_v4()'), primaryKey: true, allowNull: false, }
内容的提问来源于stack exchange,提问作者Alberto Sanmartin Martinez

