跳到主要内容

6.3-prisma

Create by fall on 25 Sep 2023
Recently revised in 23 Jun 2025

Prisma​

prisma 官方是下一代 ORM,不知道是不是可以这样说,但是 Prisma 支持主流的数据库(Postgresql、Mongodb、mysql)并且有项目组长期维护,所以也值得信任。

安装和初始化​

首先,在项目中安装 prisma,npm i prisma

使用 npx prisma version 查看版本信息

prisma 命令用于初始化和创建文件,@prisma/client 用于创建连接和数据库映射。

然后使用命令 npx prisma init,

初始化为我们提供了两个新的文件 prisma.prisma 和 .env。

一般来讲,要保证 prisma 和 @prisma/client 的版本统一,来确保行为一致,所以,全局安装 prisma 时要特别注意

连接 mongo​

在 prisma.prisma 中写入如下内容

你的架构和数据库之间的“耦合”故意设计得比 SQL 数据库更不严格;MongoDB 不会强制执行该架构,因此你必须验证数据完整性。

为了避免由于数据和架构之间不一致而导致迁移失败,解决方案之一是任何新字段都明确定义为可选。

// datasource 表示你的 prisma 如何连接到数据库
datasource db {
provider = "mongodb"
url = env("DATABASE_URL") // 使用 env 中的 DATABASE_URL 变量
}
// generator 决定了当你运行 prisma generate 命令时,在哪里创建文件
generator client {
provider = "prisma-client-js"
// output = "./generated/prisma-client-js" // 可选,自定义输出的位置
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
slug String @unique
title String
body String
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
comments Comment[]
}

首先使用命令

mongosh 进入 mongodb 的命令行界面,会提供以下内容

Current Mongosh Log ID: 6526a8a80aed2e92c3cd7fa9
Connecting to: mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+1.10.0
Using MongoDB: 5.0.18
Using Mongosh: 1.10.0

prisma 会用到 Connecting to 后面的内容,该链接可以拆解为下面的形式

mongodb://USERNAME:PASSWORD@HOST:PORT/DATABASE
# USERNAME: The name of your database user
# PASSWORD: The password for your database user
# HOST: The host where a instance is running
# PORT: The port where your database server is running (typically `27017` for MongoDB)
# DATABASE: The name of the database

我们先使用命令 use myBase 创建数据库 myBase,然后将下面的内容放到 .env 文件中

# .env 文件中添加以下内容
# 把路径 myBase 添加到上方 Connecting to 的内容中,组合成下面这样
DATABASE_URL="mongodb://localhost:6200/myBase?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+1.10.0"

最后,在 mongosh 命令行中使用 rs.initiate() 命令初始化 Replica Set

rs.initiate()
# {
# info2: 'no configuration specified. Using a default configuration for the set',
# me: '74b3cecd77b6:27017',
# ok: 1
# }

至此,连接的准备工作已经完成

连接 postgres​

// schema.prisma
generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "postgresql"
url = env("postgresql://userName:password123@localhost:5432/mydatabase?schema=public&connect_timeout=300)
}

安装 client​

npm i @prisma/client

安装过程中,也同时运行了 prisma generate 命令,生成用于 prisma 操作的类型文件。

将 prisma 命令放置到 package.json 的 script 中

"scripts": {
// ... 其它脚本
"prisma": "prisma"
}

以后,每当更改 prisma 文件的时候,都要运行 prisma generate。用来生成 node_modules/@prisma/client 库中的 Typescript 类型,之后就可以获得对应的类型提示。

对于不同类型的数据库,要使用不同的命令来向数据库提交数据格式

# 将当前数据格式提交到数据库
# 将数据模型(data model)同步到数据库中,mongo
pnpm prisma db push
# 创建索引,并且重新生成 @prisma/clinent create new indexes and regenerate Prisma Client.

# 一般关系型数据库
pnpm prisma migrate dev

配置文件​

// prisma.config.ts
import path from 'node:path'
import type { PrismaConfig } from 'prisma'

export default {
earlyAccess: true,
schema: path.join('prisma'),
} satisfies PrismaConfig<Env>

使用​

添加​

  • 创建

  • 创建新的 Post record 并且将他连接到 User record

const post = await prisma.post.create({
data: {
title: 'Join us for Prisma Day 2020',
slug: 'prisma-day-2020',
body: 'A conference on modern application development and databases.',
user: {
connect: { email: 'hello@prisma.com' },
},
}
})

同时创建 User 以及 Post

在同一查询中创建新的 User 和新的 Post 记录

const user = await prisma.user.create({
data: {
name: 'Alice',
email: 'alice@prisma.io',
posts: {
create: { title: 'Join us for Prisma Day 2020' },
},
},
})

修改​

// Run inside `async` function
const post = await prisma.post.update({
where: { id: 42 },
data: { published: true },
})

删除​

app.delete(`/post/:id`, async (req, res) => {
const { id } = req.params
const post = await prisma.post.delete({
where: {
id: Number(id),
},
})
res.json(post)
})

查找​

查询 Post 中所有包含 "hello" 的 records

const filteredPosts = await prisma.post.findMany({
where: {
// 过滤所有 title 和 body 包含 hello 的记录
OR: [{ title: { contains: 'hello' } }, { body: { contains: 'hello' } }],
},
})
// 返回每个 user 上包含 posts 的关系
const allUsers = await prisma.user.findMany({
include: { posts: true },
})

使用 fluent relations API to retrieve the Post records of a User by traversing the relations

const user = await prisma.comment
.findUnique({
where: { id: '60ff4e9500acc65700ebf470' },
})
.post()
.user()

删除一个 User record

const deletedUser = await prisma.user.delete({
where: { email: 'sarah@prisma.io' },
})

对比其它技术​

原始 SQL

对比 pg,mysql,这些工具可以实现完全控制数据库操作,但生产率低,查询结果没有类型安全

SQL 查询构建器

应用开发者仍然需要根据 SQL 来考虑他们的数据。

传统的 ORM

开发者将应用模型定义为类来抽象化 SQL,这些类映射到数据库中的表。

但实际上 ORM 会生成 SQL JOIN,这些 SQL JOIN 成本高昂,并且有可能大大减慢你的应用速度

数据建模​

process of defining the shape and structure of the objects in an application

定义应用中对象的形状和结构的过程

在对数据建模时,你通常会问以下问题:

  • 我的应用中的主要实体/概念是什么?
  • 他们之间的关系如何?
  • 它们的主要特性/特性是什么?
  • 他们如何用我的技术堆栈来表示?

参考文章​

作者链接
prisma 官方文档Connect your database (MongoDB)
prisma 对比 mongoosehttps://www.prisma.io/docs/orm/more/comparisons/prisma-and-mongoose