首页 / Prisma ORM 入门教程 / 主键、唯一约束与默认值函数

Prisma ORM 入门教程

主键、唯一约束与默认值函数

本教程共 54 篇 · 第 9 篇 · 更新于 2026-08-11 · 约 5 分钟阅读

Prisma主键@id@unique唯一约束默认值函数@updatedAtfindUnique

本节目标:学会用 @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 管组合。约束名可以用 namemap 自定义,方便数据库运维时辨认。

唯一约束配合 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)