主键、唯一约束与默认值函数
本教程共 54 篇 · 第 9 篇 · 更新于 2026-08-11 · 约 5 分钟阅读
本节目标:学会用
@id/@@id定义主键,用@unique/@@unique加唯一约束,掌握默认值函数与@updatedAt。
主键是数据的「身份证号」,用来唯一标识一行记录。Prisma 要求每个模型至少有一个唯一标识:要么是主键(@id/@@id),要么是必填的唯一字段(@unique/@@unique)。没有唯一标识,Prisma Client 就无法定位单条数据。
单字段主键:@id
最常见的写法是自增整数主键:
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
@id 标记主键,@default(autoincrement()) 让数据库自动分配递增数字。一个模型只能有一个主键,但主键可以由一个字段组成,也可以由多个字段组成。
复合主键:@@id
当单字段无法唯一标识时,用 @@id 组合多个字段:
model User {
firstName String
lastName String
email String @unique
@@id([firstName, lastName])
}
复合主键在 Prisma Client 中会被当成一个字段使用,默认名字是下划线连接的 firstName_lastName。想要更顺手的名字,用 name 参数:
model User {
firstName String
lastName String
@@id(name: "fullName", fields: [firstName, lastName])
}
Note
@id和@@id互斥,一个模型只能二选一。MongoDB 不支持复合主键(v7 不支持 MongoDB,相关内容留 v6.19)。
唯一约束:@unique 与 @@unique
唯一约束保证某字段的值不重复。邮箱、用户名、订单号这类业务标识都该加:
model User {
id Int @id @default(autoincrement())
email String @unique
}
model Post {
id Int @id @default(autoincrement())
title String
authorId Int
@@unique([authorId, title]) // 同一作者的文章标题不重复
}
@unique 管单字段,@@unique 管组合。约束名可以用 name 或 map 自定义,方便数据库运维时辨认。
唯一约束配合 findUnique 使用——findUnique 只接受唯一字段作为查询条件:
const user = await prisma.user.findUnique({
where: { email: "ada@example.com" },
});
Tip主键本身就有唯一性,所以「每个模型至少一个唯一标识」这条规则,用必填的
@unique字段也能满足(比如只用邮箱当标识的模型)。但实践中几乎总是先加id主键。
违反唯一约束时,数据库会拒绝写入,Prisma 抛出错误码 P2002(Unique constraint failed)。报错信息会明确指出哪个字段冲突,是排查重复数据的第一线索。
默认值函数逐个看
@default() 除了静态值(5、"draft"、false),还支持列表和 JSON。JSON 默认值要写成转义字符串:@default("{ \"hello\": \"world\" }")。静态值在数据库层实现,迁移 SQL 里会生成 DEFAULT 子句。
autoincrement():自增整数,适合主键。PostgreSQL 生成 SERIAL/IDENTITY 列,SQLite 是 INTEGER 自增。类型是 BigInt 时同样可用。注意它只能用于整数类型,String 主键配不上。
now():记录创建时间。它在数据库层实现,对应 CURRENT_TIMESTAMP,写进迁移 SQL,内省时也能识别。
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
}
uuid() 与 uuid(7):生成 UUID 字符串。uuid() 是 v4(随机),uuid(7) 是 v7(时间有序)。v7 按时间排序,对数据库索引更友好,是新项目首选。它在 Prisma 层实现,数据库里看不到。想要数据库层生成(配合 @db.Uuid 原生列),用 dbgenerated("gen_random_uuid()")。
cuid() 与 cuid(2):CUID 规范的可排序 ID,比 UUID 短。cuid() 约 25 字符,cuid(2) 更短更安全,适合不想用数字自增的场景。
nanoid(n):NanoID 规范,长度 2 到 255 可调,默认 21。随机位数和 UUID v4 相当,但字符更紧凑。
model User {
id String @id @default(cuid(2))
code String @default(nanoid(16))
}
Note
uuid()、cuid()、nanoid()都在 Prisma 层生成值,数据库默认值里看不到。想让数据库自己生成,用dbgenerated()。
dbgenerated(“SQL 表达式”):直接写原生 SQL 默认值,适合 Prisma 表达不了的情况。比如在数据库层生成 UUID:
model User {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
name String
}
gen_random_uuid() 是 PostgreSQL 13+ 的内置函数,更早版本需要先启用 pgcrypto 扩展。它还常用来给 Unsupported 类型(如 circle)设默认值。
Tip怎么选:想让数据库自己管默认值(其他客户端写入也生效),用
autoincrement()/now()/dbgenerated();想让 Prisma 生成、不依赖数据库,用uuid()/cuid()/nanoid()。
@updatedAt:自动更新时间
@updatedAt 让字段在每次更新记录时自动写入当前时间,创建时也会设置初始值:
model Post {
id Int @id @default(autoincrement())
updatedAt DateTime @updatedAt
}
它由 Prisma 层实现,不需要数据库配合。手动传值可以覆盖自动值。now() 和 @updatedAt 都出现在一个模型里时,一个管「创建时间」,一个管「最后修改时间」,各司其职。
参考来源
- Prisma 官方文档:Models(定义 ID、默认值、唯一字段)
- Prisma 官方文档:Prisma schema reference(@id/@@id/@unique/@@unique/@default/@updatedAt、Attribute functions)