引言
书接上文,这一节主要讲prisma orm
和postgres
在next
中的完整实现。
1、什么是orm
简单的理解就是,ORM对数据库进行了抽象
,提供更高级和贴近语言的方式,进行数据库各种操作和查询以及管理
、迁移
等,且统一了各种数据库,实现上层语言操作。
Ex:
// 原始sql伪代码
INSERT INTO "Conversation" ("id", "userId")
VALUES (:id, :userId);
UPDATE "User"
SET "settings" = :settings
WHERE "id" = :userId;
await prisma.conversation.create({
data: {
id,
userId: session.user.id
}
})
await prisma.user.update({
where: { id: userId },
data: {
settings
}
})
ORM
通过提供更高级的抽象,简化了这些操作,同时保持了对底层 SQL
的控制,在更复杂的场景下会体现得更好。
2. 数据库创建
我们直接通过docker
和docker-compose
来创建数据库。我写过一篇有关容器的文章(删了后面一部分,那后面是go的容器扩展开发,有兴趣的也可以来讨论一下)可以简单看一下。
首先我们在根目录下创建一个.env
文件包含以下内容:
POSTGRES_DB=you_db_name
POSTGRES_USER=you_db_user
POSTGRES_PASSWORD=your_strong_password_here
POSTGRES_PORT=5988
默认行为: Docker Compose 默认会查找当前目录中名为 .env 的文件,并自动加载其中定义的环境变量。这是内置的行为。
关于密码、用户名、端口的问题:请不要使用默认这种postgres
的db name
和user
。以及最重要的端口,请不要默认5432:5432
。都是一些安全教训了。
紧接着让我们在根目录下创建 docker-compose.db.yml
文件:
Ex:
version: '3.8'
services:
db:
image: postgres:15
command:
- 'postgres'
- '-c'
- 'max_connections=1000'
shm_size: '4gb'
container_name: postgres-container
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "${POSTGRES_PORT}:5432"
volumes:
postgres_data:
就让我们跑起来吧!
docker-compose -f docker-compose.db.yml up -d
这个命令指定使用 docker-compose.db.yml
文件,并在后台启动 PostgreSQL 容器。
当我们输入 docker ps
可以看到这个容器
Ex:
紧接着我们就可以在数据库工具
中链接啦。
当我们需要停止或重启数据库时,使用以下命令:
# 停止数据库
docker-compose -f docker-compose.db.yml down
# 重启数据库
docker-compose -f docker-compose.db.yml up -d
当我们已经配置好数据库,接下来的一步就来到了Prisma
链接数据库,创建表结构了~。
2、prisma使用
依赖安装
首先,让我们安装必要的依赖:
pnpm add @prisma/client
pnpm add prisma -D
这个命令会安装 Prisma CLI
和 Prisma Client
。
Schema 和数据库的关系
Prisma schema
是 Prisma
的核心概念之一。它是一个声明性文件,用于定义我们的数据库和 Prisma Client
的生成。
- Schema 定义:
Schema 文件通常命名为schema.prisma
,它定义了你的数据模型、数据源(数据库连接)和生成器(用于生成 Prisma Client)。 - 数据模型映射:
在 schema 中定义的模型直接映射到数据库中的表。例如,如果你定义了一个User
模型,Prisma 会在数据库中创建一个对应的User
表。 - 字段和列:
模型中的每个字段对应数据库表中的一列。Prisma 会根据字段的类型自动选择适当的数据库列类型。 - 关系:
Prisma schema 允许你定义模型之间的关系,这些关系会被转换为数据库中的外键关系。 - 数据库迁移:
当你修改 schema 文件时,Prisma 可以生成和应用数据库迁移,以保持数据库结构与你的 schema 定义同步。
让我们创建一个叫做prisma
的文件夹,然后再创建schema.prisma
文件,和client
文件。
schema.prisma
可以如下
Ex:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
这个 schema 定义了两个模型:User
和 Post
,它们之间有一个一对多的关系。
接下来,你需要设置数据库连接。在你的 .env
文件中添加:
DATABASE_URL="postgresql://username:password@localhost:5988/your_database_name"
确保替换 username
、password
和 your_database_name
为你实际的数据库配置。
然后,你可以使用 Prisma CLI
来创建数据库表:
pnpm prisma migrate dev --name init
// 或者
pnpm prisma db push
db push
它直接将你的 Prisma schema
变更推送到数据库,而不创建迁移文件, 适用于开发阶段,特别是在频繁修改数据模型时, 因为不创建迁移文件,所以无法回滚更改。 第一次创建的init数据库的时候其实也可以直接db push
migrate dev
会创建一个新的迁移,应用它到数据库,并自动执行 prisma generate
生成 Prisma Client
。
Now, 你的数据库结构已经与 Prisma schema
同步,你可以开始使用 Prisma Client
来进行数据库操作了。
记住,每次你修改 schema 文件后,都需要运行 pnpm prisma migrate dev --name your_change
来更新 Prisma Client
,以反映最新的 schema
更改。
这就是 Prisma schema
和数据库之间关系。Prisma
通过 schema
文件提供了一种强大而直观的方式来定义和管理你的数据库结构。
有关deploy
前面顺手讲了一些脚手架命令,但还有一个比较重要的命令是:prisma migrate deploy
。
pnpm prisma migrate deploy
是 Prisma
提供的一个用于生产环境的数据库迁移命令。这个命令的主要目的是将你的数据库schema
更新到最新版本,通常在生产环境或其他非开发环境中使用。
- 用途:
-
- 应用所有待处理的迁移到数据库。
- 通常用于生产环境或任何需要以可预测和可控方式更新数据库的环境。
- 工作原理:
-
- 读取
prisma/migrations
目录中的所有迁移文件。 - 检查数据库中的
_prisma_migrations
表,确定哪些迁移尚未应用。 - 按顺序应用所有未应用的迁移。
- 读取
- 特点:
-
- 不会生成新的迁移文件。
- 不会修改你的 Prisma schema 文件。
- 不会重新生成 Prisma Client。
- 安全性:
-
- 在应用迁移之前,会检查数据库的当前状态是否与预期一致。
- 如果检测到数据库状态与预期不符,会停止迁移过程并报错。
- 使用场景:
-
- 在 CI/CD 流程中自动更新数据库schema。
- 在生产服务器上手动更新数据库schema。
- 使用方法:
pnpm prisma migrate deploy
7. 最佳实践:
-
- 在应用迁移之前,始终备份你的数据库。
- 在生产环境应用迁移之前,先在类似的测试环境中测试。
- 确保所有的迁移都已经在开发环境中经过测试和验证。
- 注意事项:
-
- 这个命令不会创建新的迁移或修改现有的迁移。
- 如果你需要在生产环境中创建新的迁移,应该先在开发环境中创建和测试,然后将迁移文件提交到版本控制系统。
- 与
prisma migrate dev
的区别:
-
migrate dev
用于开发环境,会创建新的迁移文件。migrate deploy
只应用现有的迁移,不创建新的迁移文件。
使用 pnpm prisma migrate deploy
可以确保你的生产数据库schema始终与你的应用程序代码同步,同时提供了一种安全和可控的方式来管理数据库变更。
Prisma客户端使用和基础
让我们遵循官网的最佳实践,这可以解决,Next.js
的热重载功能会频繁地重新加载模块,以立即反映代码更改。但是,这会导致创建 Prisma Client
的多个实例,从而导致意外行为。
而下面的代码也就是prisma/client.ts
的内容,解决了这个问题,并且抛出了prisma
,也是我们后面使用的。
SourceCode:
import { PrismaClient } from '@prisma/client'
const prismaClientSingleton = () => {
return new PrismaClient()
}
declare global {
// eslint-disable-next-line no-var
var prisma: undefined | ReturnType<typeof prismaClientSingleton>
}
const prisma = globalThis.prisma ?? prismaClientSingleton()
export default prisma
if (process.env.NODE_ENV !== 'production') globalThis.prisma = prisma
接下来我们就可以使用prisma
进行操作了
Ex:
await prisma.user.update({
where: { email: token.email },
data: {
subscriptions: {
create: FreePlan
}
}
})
结束
项目在github上。
也可以加群大家一起闲聊、探讨、赚钱都挺好的。