prisma初体验

12/20/2023 1239 阅读需要6分钟
0
0
AI总结
Prisma 是一个现代化的 Node.js 和 TypeScript ORM 库,用于简化数据库操作,支持多种数据库如 PostgreSQL、MySQL 等。它通过类型安全和简洁的 API 提高开发效率,减少样板代码。优点包括类型安全、简洁的 API 和强大的查询构建能力,但可能存在性能开销和学习曲线。安装 Prisma 后,通过 `npx prisma init` 初始化项目,生成 `schema.prisma` 文件配置数据库连接和模型。创建数据模型后,使用 `npx prisma migrate dev --name init` 进行数据库迁移。通过封装 Prisma 客户端工具函数,可以在项目中使用 Prisma 进行数据库操作,如用户登录模块中的用户查询、更新和新增操作。

Prisma 初体验

prisma 是一个现代化的 Node.js 和 TypeScript 的 ORM(对象关系映射)库。

用途:

  1. 简化数据库操作:它提供了一种直观且类型安全的方式来与数据库进行交互,使得开发者可以通过 JavaScript/TypeScript 对象来操作数据库中的数据,而无需直接编写复杂的 SQL 语句。
  2. 提高开发效率:减少了数据库操作相关的样板代码,让开发者能够更专注于业务逻辑的实现。
  3. 支持多种数据库:如 PostgreSQL、MySQL、SQLite 等,增加了应用的可扩展性和灵活性。

优点:

  1. 类型安全:利用 TypeScript 的类型系统,在编译时就能检测到类型错误,提高代码的可靠性。
  2. 简洁的 API:提供了简洁、易于理解和使用的 API,降低了数据库操作的学习成本。
  3. 强大的查询构建:可以方便地构建复杂的查询,并且能够自动处理关联和关系。

缺点:

  1. 性能开销:相对于直接编写原生的 SQL 语句,可能会存在一定的性能开销。
  2. 学习曲线:对于初次接触 ORM 概念的开发者来说,可能需要一些时间来理解和掌握其工作原理和用法。
  3. 某些复杂操作受限:对于一些非常特殊或复杂的数据库操作,可能不如直接编写 SQL 灵活。

总体而言,Prisma 在提高开发效率和代码质量方面具有显著优势,但在对性能要求极其严格或遇到非常特殊的数据库操作需求时,需要谨慎权衡其使用。

安装

本次是在我的博客项目中替换数据库,所以直接安装即可,无需初始化一个项目。

npm install prisma
# or
yarn add prisma
# or
pnpm add prisma

然后执行npx prisma init,这个命令会执行两件事情。

  • 创建一个名为 prisma 的新目录,其中包含一个名为 schema.prisma 的文件,该文件包含了prisma schema以及数据模型
  • 创建一个.env文件在更目录下

出现下面的 log 就初始化成功了,这时候我们可以看到产生了一个 prisma 目录以及schema.prisma文件和.env.

prisma-init

数据库配置

我们可以看看刚刚创建的schema.prisma文件的内容.

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

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

其中一个是generator client一个是datasource db,client是生成客户端代码,database是数据库连接信息。

创建 Model

我用数据库的功能,主要是想做博客的点赞,查看数据等等。

所以我们需要创建User, Post的 model,还有转发和 commont 的以后再做,由于我的博客,用的是 mdx,所以不需要存储内容等信息。只用给文章生成一个 id 保存到数据库即可,用于对其它数据做关联。

model Post {
  blog_id     Int    @id @default(autoincrement())
  blog_key    String
  blog_title  String
  likes_count Int[]
  views_count Int
}

model User {
  id         Int      @id @default(autoincrement())
  email      String   @unique
  created_at DateTime @default(now())
  updated_at DateTime @default(now()) @updatedAt
  password   String
  name       String
  image      String   @default("https://blog-1302483222.cos.ap-shanghai.myqcloud.com/images.jpg")
}

这样我们就创建好了数据模型了。

运行数据库迁移

这里先需要安装pnpm add @prisma/client,用来生成 prisma 客户端。

prisma-client-install-and-generat

这是 prisma 官方文档的流程截图,我们只需要执行npx prisma migrate dev --name init命令就生成 sql 文件,在我们的数据 prisma 目录下,每次变更的话建议执行此命令,name参数需要变更,变更内容为本次修改数据库的备注。

使用

我们需要创建一个工具函数,来封装一下。

import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

export default prisma;

接下来我们可以愉快的使用 prisma 了。

我现在登录模块中使用一下,这样我们就完成了,用户在使用 github 登录的时候,没有用户就去新增用户,有的话,如果头像和名字发生了变更就去更新。

import GitHubProvider from "next-auth/providers/github";
import GoogleProvider from "next-auth/providers/google";
import CredentialsProvider from "next-auth/providers/credentials";
import { decrypt, encrypt } from "@/lib/crypto";
import { AuthOptions } from "next-auth";
import prisma from "./pg";

export const authOptions: AuthOptions = {
  secret: process.env.SECRET_KEY,
  debug: true,
  providers: [
    GitHubProvider({
      clientId: process.env.GIT_CLIENT_ID as string,
      clientSecret: process.env.GIT_CLIENT_SECRET as string,
      httpOptions: {
        timeout: 100000,
      },
      async profile(profile) {
        try {
          // 查询是否有
          const existingUser = await prisma.user.findUnique({
            where: { email: profile.email },
          });

          // 更新
          if (
            existingUser &&
            (existingUser.image !== profile.avatar_url ||
              existingUser.name !== (profile.name || profile.login))
          ) {
            await prisma.user.update({
              where: { email: profile.email },
              data: {
                name: profile.name || profile.login,
                image: profile.avatar_url as string,
              },
            });

            return existingUser as any;
          }

          // Create new user

          // 新增
          const res = await prisma.user.create({
            data: {
              name: profile.name || profile.login,
              email: profile.email,
              image: profile.avatar_url,
              password: encrypt(profile.id.toString()), // Use GitHub ID as default password
            },
          });

          return res as any;
        } catch (e: any) {
          console.log(e.message);
        }
      },
    }),
  ],
  session: {
    strategy: "jwt",
    maxAge: 2 * 24 * 60 * 60,
  },
  callbacks: {
    session: async (data: { session: any }) => {
      return data.session;
    },
  },

  pages: {
    signIn: "/",
  },
};