自学内容网 自学内容网

【NextJS】PostgreSQL 遇上 Prisma ORM

前言

Next.js 全栈开发的时候不免要用到数据库,采用原生数据库语法可能还需要顾虑很多方面的问题(语法安全、原生语法麻烦/繁琐/复杂、更换数据库时的语法兼容等等),为了解决这类问题诞生了ORM‌(Object-Relational Mapping)数据访问方式技术及周边工具;

这里介绍一个易用又强大的ORM‌框架/工具库:Prisma ORM

官网:https://www.prisma.io/
GitHub:https://github.com/prisma/prisma

内容包含以下两个部分:

  • 重点概念

    • Prisma Schema Language (PSL).:用来描述数据库架构的语言
  • 两个主要(常用)操作库

    • Prisma Client:为 Node.js 和 TypeScript 自动生成类型安全的查询生成器
      可用于任何Node.jsTypeScript 后端应用程序(包括无服务器应用程序和微服务)。
    • Prisma Migrate:声明式数据建模和迁移系统
      主要用于生产部署、数据迁移等应用场景
    • Prisma CLI:辅助快捷的操作命令工具

延展辅助(平台服务):

  • Prisma Postgres[链接]:托管的 PostgreSQL 数据库服务
  • Prisma Accelerate[链接]:针对现有数据库的完全托管的全局连接池和缓存层,可直接从 Prisma ORM 支持查询级缓存策略。
  • Prisma Optimize[链接]:针对数据操作,基于AI进行优化分析服务
  • Prisma Studio[链接]:用于查看和编辑等操作的数据库可视化GUI工具

一、环境要求

最新环境要求可前往官方文档:https://www.prisma.io/docs/orm/reference/system-requirements

软件:

工具最低要求版本
Node.js18.8 / 20.9 / 22.11
TypeScript (可选)5.1.X
Yarn (可选)1.19.2(当使用Yarn 1时)

操作系统:

Linux:

  • OpenSSL 1.0.x、1.1.x 或 3.x
  • zlib(libz.so.1)
  • libgcc( libgcc_s.so.1)
  • C 标准库(大多数 Linux 发行版上的 glibc 或 Alpine Linux 上的 musl libc)

Windows:

macOS:

  • macOS 10.15 或更新版本

二、概念介绍

1、Prisma Schema Language(PSL) 结构描述语言

1.1 概念

Prisma Schema Language(简称:PSL) - Prisma ORM 的核心部分
用于定义数据库模型关系、以及生成 Prisma Client 的配置文件

想要将架构拆分为多个文件? Prisma ORM 5.15.0 及更高版本中的 prismaSchemaFolder 预览功能 支持多文件 Prisma Schema 。

它是一个声明式语言,通过定义 .prisma 文件来描述数据库结构关系
Prisma Client将基于(PSL)生成数据库交互代码。

1.2 组成

  • Data Source:数据库源(例如:PostgreSQL or MongoDB…)
  • Generators:数据模型生成器(例如:Prisma Client)
  • Data model definition:数据模型定义(例如,user数据表有哪些字段、分别什么数据类型等)
1.2.1 Data Source 数据源

定义数据库的连接信息,通常包括数据库的类型(例如PostgreSQL、MySQL、SQLite等)、连接URL、以及数据库的其他配置。

示例:

datasource db {
  provider = "postgresql" // 指定 PostgreSQL 作为数据库
  url      = env("DATABASE_URL") // 从环境变量 DATABASE_URL 获取连接字符串
}
1.2.2 Generators 生成器

定义生成器的配置,Prisma默认使用生成Prisma Client。
通常会在此配置生成的Prisma Client存放的位置,以及语言(TypeScript/JavaScript)。

示例:

generator client {
  provider = "prisma-client-js"
  output   = "./generated/client"
}
1.2.3 Data Model Definition 数据模型定义

定义数据库中的实体(表)。每个model对应数据库中的一个表,表的字段对应model中的属性
可以定义字段的类型默认值约束(如@id@unique等)以及关系(如@relation)。

model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  name  String
  posts Post[]
}

model Post {
  id      Int    @id @default(autoincrement())
  title   String
  content String?
  author  User   @relation(fields: [authorId], references: [id])
  authorId Int
}
字段(数据)类型和约束

每个字段可以指定数据类型,支持多种类型,如IntStringBooleanDateTimeFloatDecimal等。
可以通过@default()设置默认值,@unique设置唯一约束,@id定义主键等。

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  published Boolean  @default(false)
  createdAt DateTime @default(now())
}
关系(Relations)

PSL支持定义实体之间的关系。常见的关系包括一对一(1:1)一对多(1:N)多对多(M:N)。通过@relation定义。

// 示例:一对多关系

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id      Int    @id @default(autoincrement())
  userId  Int
  author  User   @relation(fields: [userId], references: [id])
}
枚举(Enum)

PSL还支持枚举类型,用于表示有多个固定选项的字段。

// 示例

enum Role {
  USER
  ADMIN
  MODERATOR
}

model User {
  id    Int    @id @default(autoincrement())
  name  String
  role  Role
}

更多数据模型内容可以前往官方文档探索:https://www.prisma.io/docs/orm/prisma-schema/data-model

2、Prisma Client 数据交互接口

2.1 概念

Prisma ClientPrisma ORM 的主要组成部分,它是一个自动生成的数据库查询客户端,用于与数据库进行交互。
提供一种类型安全的方式来执行数据库操作,简化与数据库的连接和操作。

关键特点:

  • 自动生成:根据数据库模式(schema.prisma 文件)自动生成一个类型安全的客户端库(代码)
  • 类型安全:使用 TypeScript 来生成类型定义,这意味着在开发过程中,可以获得类型推导和自动补全,数据操作无需手动编写原始SQL语法交由Prisma Client 提供的 API 使用 JavaScript/TypeScript 中的类型安全语法
  • 完善接口(API):包含CRUD、关联、分页和排序、事务操作等
  • 数据库支持PostgreSQLMySQLMariaDBSQL ServerSQLiteCockroachDBMongoDB 各类主流数据库

2.2 使用示例

  1. 定义数据库模型(schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id    Int    @id @default(autoincrement())
  name  String
  email String @unique
}
  1. 模型构建
pnpx prisma generate
  1. 在代码中使用
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

async function main() {
  const users = await prisma.user.findMany();
  console.log(users);
}

main().catch(e => {
  throw e
}).finally(async () => {
  await prisma.$disconnect()
});

3、Prisma Migrate 迁移与种子

3.1 概念

Prisma MigratePrisma ORM 中用于数据库迁移的工具。
通过自动生成和执行 SQL 迁移脚本来管理数据库结构变化,同时确保数据库结构与 Prisma Schema 文件(schema.prisma)保持一致。

3.2 迁移流程

Prisma ORM 的集成数据库迁移工具-工作流程
通常的工作流程包括以下几个步骤:

  • 修改 Prisma 模式:你在 schema.prisma 文件中修改数据库模型。
  • 创建迁移文件:运行 prisma migrate devprisma migrate create 命令,自动生成迁移文件。
  • 应用迁移:通过 prisma migrate deployprisma migrate dev 将迁移应用到数据库。
  • 查看迁移历史:Prisma 会在数据库中跟踪迁移历史,确保每次迁移都按顺序应用。

3.3 数据库迁移(Migrate)

3.3 数据种子(Seeding)

4、Prisma CLI 命令行工具

init

参数默认描述
--datasource-providerpostgresql指定块provider中字段的值datasource。选项包括sqlite、postgresql、mysql、和。sqlservermongodbcockroachdb
--url定义自定义数据源 URL
--with-model在初始 Prisma 模式中添加一个简单的用户模型。自 5.14.0 版起可用
--outputnode_modules/.prisma/client指定生成的客户端的输出位置
--generator-providerprisma-client-js定义要使用的生成器提供程序
--preview-feature定义要使用的预览功能

示例:

pnpx prisma init --datasource-provider PostgreSQL

generate

参数默认描述
--no-engine生成不带附带引擎的 Prisma Client 以与Prisma Accelerate–data-proxy一起使用。与和互斥–accelerate。在 Prisma ORM 5.2.0 及更高版本中可用。
--no-hints生成 Prisma Client,但不会在终端上打印使用提示。在 Prisma ORM 5.16.0 及更高版本中可用。
--allow-no-models将生成 Prisma Client,但不生成任何模型
--watch监视schema.prisma文件并在文件更改时重新生成 Prisma Client

示例:

prisma generate

其他的后续再整理补充…

三、Next.js 中应用示例

Next.js + PostgreSQL 组合为例!

node环境:

  • node:v20.17.0
  • pnpm:9.15.3

1、全新项目示例

1.1 项目初始化

  • react:^19.0.0
  • next:15.1.4
  • pg:^8.13.1
  • @prisma/client:^6.2.1
pnpx create-next-app@latest

// 安装时,将看到以下提示:
✔ What is your project named? … .
✔ Would you like to use TypeScript? … Yes
✔ Would you like to use ESLint? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like your code inside a `src/` directory? … No
✔ Would you like to use App Router? (recommended) … Yes
✔ Would you like to use Turbopack for `next dev`? … No
✔ Would you like to customize the import alias (`@/*` by default)? … No

增加依赖包:pg@prisma/client

pnpm add pg @prisma/client

1.2 初始化Prisma ORM

// 初始化兼容PostgreSQL驱动数据库
pnpx prisma init --datasource-provider PostgreSQL

// 将看到以下提示:
✔ Your Prisma schema was created at prisma/schema.prisma
  You can now open it in your favorite editor.

warn You already have a .gitignore file. Don't forget to add `.env` in it to not commit any private information.

Next steps:
1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
2. Run prisma db pull to turn your database schema into a Prisma schema.
3. Run prisma generate to generate the Prisma Client. You can then start querying your database.
4. Tip: Explore how you can extend the ORM with scalable connection pooling, global caching, and real-time database events. Read: https://pris.ly/cli/beyond-orm

More information in our documentation:
https://pris.ly/d/getting-started

至此,基础环境搞定,接下来重点查看编辑两个文件:.envprisma/schema.prisma
在这里插入图片描述
.env文件中,重点设置DATABASE_URL的值,用于建立数据库连接的配置

DATABASE_URL="postgresql://[username]:[password]@[ip|domain]:[port|5432]/[database][?param1=value1&param2=value2&...]"

prisma/schema.prisma文件中,对生成器、数据模型进行配置

generator client {
  provider = "prisma-client-js"
  output   = "./client"   // 配置生成器的代码生成位置(相对schema.prisma文件所在目录)
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

// 以下部分均为数据模型构建配置
model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  name  String
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String
  published Boolean
  user      User    @relation(fields: [userId], references: [id])
  userId    Int
}

完成以上配置后,开始生成Prisma客户端代码:

// 生成Prisma客户端
pnpx prisma generate

// 将看到以下提示:
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma

✔ Generated Prisma Client (v6.2.1) to ./prisma/client in 24ms

Start by importing your Prisma Client (See: https://pris.ly/d/importing-client)

Tip: Need your database queries to be 1000x faster? Accelerate offers you that and more: https://pris.ly/tip-2-accelerate

在这里插入图片描述

1.3 数据迁移

将数据模型推送到数据库中

// 模型推送
pnpx prisma db push

// 将看到以下提示:
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "xxxx", schema "public" at "xxxx:5432"

🚀  Your database is now in sync with your Prisma schema. Done in 6.22s

✔ Generated Prisma Client (v6.2.1) to ./prisma/client in 28ms

1.4 播种数据(可选)

添加ts-node@types/node到开发依赖项

pnpm add -D ts-node @types/node

Ps:非TypeScript项目需要增加typescript依赖包

prisma目录下创建一个seed.ts文件,写入播种数据

// 导入 PrismaClient(注:pnpx prisma generate生成的代码)
import { PrismaClient } from './client'

// 创建 PrismaClient 实例
const prisma = new PrismaClient()

// 定义 main 函数
async function main() {
    // 使用 upsert 方法创建或更新用户
    const alice = await prisma.user.upsert({
        where: { email: 'alice@prisma.io' },
        update: {},
        create: {
            email: 'alice@prisma.io',
            name: 'Alice',
            posts: {
                create: {
                    title: 'Check out Prisma with Next.js',
                    content: 'https://www.prisma.io/nextjs',
                    published: true,
                },
            },
        },
    })
    // 创建另一个用户
    const bob = await prisma.user.upsert({
        where: { email: 'bob@prisma.io' },
        update: {},
        create: {
            email: 'bob@prisma.io',
            name: 'Bob',
            posts: {
                create: [
                    {
                        title: 'Follow Prisma on Twitter',
                        content: 'https://twitter.com/prisma',
                        published: true,
                    },
                    {
                        title: 'Follow Nexus on Twitter',
                        content: 'https://twitter.com/nexusgql',
                        published: true,
                    },
                ],
            },
        },
    })
    console.log({ alice, bob })
}

// 执行 main 函数并处理错误
main()
    .then(async () => {
        await prisma.$disconnect()
    })
    .catch(async (e) => {
        console.error(e)
        await prisma.$disconnect()
        process.exit(1)
    })

package.json文件中新增以下配置,告诉prisma播种文件所在位置及其他配置信息

{
  // .....
  "prisma": {
    "seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
  },
  // .....
}

将种子数据推送上数据库里

// 种子推送
pnpx prisma db seed

// 将看到以下提示:
Environment variables loaded from .env
Running seed command `ts-node --compiler-options {"module":"CommonJS"} prisma/seed.ts` ...
{
  alice: { id: 1, email: 'alice@prisma.io', name: 'Alice' },
  bob: { id: 2, email: 'bob@prisma.io', name: 'Bob' }
}

🌱  The seed command has been executed.

在这里插入图片描述

1.5 模拟业务

创建一个api接口GET /api/users 用于获取用户表所有数据

1、实例化 Prisma 客户端

prisma目录创建一个db.ts文件,用于实例化
在这里插入图片描述

// file:/prisma/db.ts

import {PrismaClient} from './client'

const globalForPrisma = globalThis as unknown as { prisma: PrismaClient }

export const prisma = globalForPrisma.prisma || new PrismaClient()

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma

export default prisma

2、创建数据API接口
在这里插入图片描述

"use server";

import {NextResponse} from 'next/server'
// 导入客户端实例
import prisma from "@/prisma/db"

export async function GET() {
// 使用findMany方法获取user表相关数据
    const allUsers = await prisma.user.findMany();

    return NextResponse.json({
        message: 'Hello World',
        data: allUsers
    }, {status: 200});
}

3、测试获取是否正常
在这里插入图片描述


有何不足之处欢迎评论区或者私信我


原文地址:https://blog.csdn.net/u011159821/article/details/145182483

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!