四、Prisma操作数据库
Prisma 是 Nodejs, TypeScript 的下一代数据库 ORM
由以下几部分组成:
Prisma Client- 类型安全的查询生成器Prisma Migrate- 迁移工具Prisma Studio- 数据库GUI
我们本章节不会涉及到过多的内容 , 专注于以下几点:
Schema- 数据库的表结构定义Client- 客户端工具CRUD的基本用法Migrate- 数据迁移的操作方法
安装prisma
- 安装依赖:
1 | pnpm add ts-node prisma -D |
- 初始化
prisma
1 | npx prisma init |
此命令做了两件事:
- 在根目录下创建一个名为
prisma的文件夹且其中包含一个文件schema.prisma- 在根目录下创建
.env文件
- 连接数据库
默认创建的
schema使用的是PostgreSQL,我们后续以MySQL做演示
在schema.prisma中指定数据库:
1 | // prisma/schema.prisma |
在.env中配置数据库链接:
1 | // .env |
快速上手
- 定义
schema
在prisma/schema.prisma中添加数据模型
1 | model Post { |
- 数据模型映射到数据库架构
1 | npx prisma migrate dev --name init |
此命令执行两项操作:
为这次迁移创建了一个新的SQL迁移文件
对数据库运行SQL迁移文件
注意:默认情况下,在运行
prisma migrate dev之后,会调用generate(generate会根据schema生成TypeScript类型声明)。如果你的模式中定义了prisma-client-js生成器,这将检查@prisma/client是否已经安装,如果它没有安装,就安装它。
- 安装
prisma client
1 | pnpm add @prisma/client |
安装命令会自动调用prisma generate,它会读取prisma模式并生成一个适合您的模型的prisma Client版本。
以后每当您对
Prisma架构进行更改时,您都需要手动调用prisma generate以适应Prisma客户端API中的更改。
- 操作数据库
1 | import { PrismaClient } from '@prisma/client' |
这里只是做了个快速上手
demo,接下来我们会演示在Nextjs中使用prisma的方式
Nextjs使用prisma
前边做了快速上手示例,但是在Nextjs中直接这么使用是不合适的,如果按照上边的方式,在使用nextjs开发中,next dev 会在运行时清除 Node.js 缓存。这反过来又会初始化一个新的 PrismaClient 实例,因为热重载会创建与数据库的连接。这会快速耗尽数据库连接,因为每个 PrismaClient 实例都拥有自己的连接池。
在这种情况下,解决方案是实例化单个实例 PrismaClient 并将其保存在globalThis对象。然后,我们检查仅实例化 PrismaClient(如果它不在 globalThis 对象上),否则如果已经存在,请再次使用相同的实例,以防止实例化额外的 PrismaClient 实例。
我们在db/prisma.ts中对其进行封装:
1 | // db/prisma.ts |
只有开发环境才有这个问题,所以我们执行了
if (process.env.NODE_ENV !== 'production') globalThis.prisma = prisma保证开发环境下把prisma保存到全局对象,避免重复创建。生产环境下不会有热重载等情况,也就不存在这个问题了。
之后,我们在需要操作数据库的地方,就可以导入这个封装后的prisma来使用了。
Schema
Prisma Schema文件是核心配置文件,命名为prisma.schema,包含三个部分:
datasource- 配置数据库generator- 目前仅支持provider=prisma-client-jsmodel- 实体
Model 定义:
- 表示应用的
entity实体 - 映射成数据库的
table(在mongo中映射为collection) - 是
prisma client api使用的基础 - 如果使用
typescript,会为model生成类型定义。
有以下部分组成:
- 包含多个字段(包括模型关系)
- 枚举
- 更改字段和模型行为的属性和函数
模型与表的映射
prisma模型命名约定为单数形式,大驼峰,而数据库中的命名方式一般是复数形式,下划线分隔。
所以我们一般需要进行表名或字段名的映射
可以使用@@map来自定义命名表名。用@map来自定义字段名
1 | // prisma/prisma.schema |
在客户端进行使用的时候会使用小写形式,比如模型Comment则client.comment,模型CommentPage则使用client.commentPage这样子。字段名还是以模型中定义的形式来使用,@map只是对于数据库中表字段的映射
定义字段
字段由以下几部分组成:
- 字段名称
- 字段类型
- 可选的类型修饰符
- 可选的属性
可以通过以下两个修饰符来修改字段的类型:
[]- 将字段设为列表?- 将字段设为可选
不能组合类型修饰符,即不支持可选的列表
定义ID
ID 唯一标识模型的各个记录。一个模型只能有一个 ID:
- 在关系数据库中,
ID可以是单个字段,也可以基于多个字段。如果模型没有@id或@@id,则必须改为定义必填@unique字段或@@unique块。 - 在MongoDB中,
ID必须是定义@id属性和@map("_id")属性的单个字段。
在关系型数据库定义ID
- 单字段ID
1 | model User { |
- 复合ID
1 | model User { |
默认情况下,Prisma 客户端查询中此字段的名称将firstName_lastName.
您还可以使用@@id属性name复合 ID 提供自己的名称:
1 | model User { |
firstName_lastName字段现在将改为命名为 fullName。
定义字段属性
属性修改字段或模型模块的行为。以下示例包括三个字段属性(@id、@default 和 @unique )和一个块属性 (@@unique ):
1 |
|
常见字段属性:
通过
@default定义默认值,可以使用常量值和prisma提供的函数。通过
@unqiue实现唯一值。通过模型上的
@@index在模型的一个或多个字段上定义索引
枚举
如果数据库连接器支持,则可以在数据模型中定义枚举
1 | model User { |
CRUD
常用的CRUD方法:
findManyfindFirstfindFirstOrThrowfindUniquefindUniqueOrThrowcreateupdateupsertdeletecreateManyupdateManydeleteMany
这些操作可通过 Prisma 客户端实例上生成的属性进行访问。默认情况下,属性的名称是模型名称的小写形式,例如,用户
User模型的user或Post模型的post。使用时比如await prisma.user.findFirst(...)更改
schema后记得执行generate命令,才能获得TypeScript类型提示哦
Migrate
我们经常会用到的命令有migrate和db push
Prisma Migrate:Prisma Migrate是一个迁移工具,可以轻松地将数据库模式从原型设计应用到生产。- 它主要用于处理数据库模式的变更,包括添加、修改或删除表、索引和其他数据库对象。
- 通过
Prisma Migrate,你可以在schema.prisma文件中定义模型,并将其迁移到数据库中。如果存在冲突,它将根据schema中的定义进行重置。 - 你还可以使用
Prisma Migrate进行开发环境的迁移,将更改部署到暂存、测试和生产环境。它只运行迁移文件,你可以选择只生成迁移文件而不自动执行,以便进行人工修改。
Prisma DB Push:Prisma DB Push是一个命令行工具,用于推送数据库结构变更。- 该命令可以删除并重新创建数据库,或者通过删除所有数据、表、索引和其他来进行重置。
- 在某些情况下,你可能需要完全重置数据库并重新创建其结构。这时,你可以使用
Prisma DB Push来实现这一目标。
总结:
Prisma Migrate主要用于处理数据库模式的变更,可以根据需要进行迁移和开发环境的部署。Prisma DB Push则用于完全重置和重新创建数据库。
在使用时,你可以根据具体需求选择合适的工具。如果你需要处理数据库模式的变更并部署到不同环境,可以使用 Prisma Migrate。而如果你需要完全重置数据库,可以使用 Prisma DB Push。
prisma migrate不适用于mongo,请在mongo中使用db push
实例
目前为止,我们已经接触到了Nextjs, ShadcnUI, React Query, Prisma,在下一个章节, 我们基于这些知识做一个小的案例来试一下。