NestJS和Prisma:一个强大的组合

一、前言

在本文中,我将介绍如何在NestJS中使用Prisma。Prisma是一个用于构建和管理数据库的工具,它可以与NestJS无缝集成,提供了一个强大和类型安全的查询语言,以及更加便捷的数据库CURD,具体使用请阅读本文。

二、 Prisma

本文基于mysql关系型数据库进行讲解,如需非关系型数据库的讲解,如MongoDB,请移步 从头开始使用 MongoDB

1.安装所需包

ruby 复制代码
$ pnpm i prisma@5.5.2
$ pnpm i @prisma/client@5.5.2

2.初始化

csharp 复制代码
$ npx prisma init

执行以上命令会创建.env文件与prisma文件夹

  • .env 用于定义数据库连接
  • prisma用于定义模型结构与数据迁移与数据填充文件

3.连接数据库

修改.env文件设置mysql连接,以下连接请根据你的情况修改

.env 复制代码
    DATABASE_URL="mysql://root:root@localhost:3306/databasename"
    #定义环境
    NODE_ENV=development

注:databasename 是指你的数据库名,例如:mydatabase

4.迁移文件

迁移文件migrate用于构建数据表结构变化,他是数据库的版本控制机制,每次表结构的修改都有单独文件记录。

1.结构定义

在 prisman/schema.prisma 文件内定义表结构,你可以查看数据模型或 字段类型文档了解使用方法。本文重点在于从已创建好的数据库中迁移至prisma,以下仅做手动建表的示例,详细请查看Prisma 架构(参考)

schema.prisma 复制代码
    generator client {
      provider = "prisma-client-js"
    }

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

    model user {
      //BigInt类型	主键 自增值	非负BitInt
      id       BigInt    @id @default(autoincrement()) @db.UnsignedBigInt()
      //字符串,默认为varchar(191)
      email    String
      password String
      //添加时自动设置时间,即设置Mysql默认值为CURRENT_TIMESTAMP
      createdAt DateTime @default(now())
      // 让Prisma在添加与更新时自动维护该字段
      updatedAt DateTime @updatedAt
    }

2.生成迁移

①手动迁移

要将数据模型映射到数据库模式(即创建相应的数据库表),你需要使用 prisma migrate CLI 命令

csharp 复制代码
$ npx prisma migrate dev --name init

该命令做了两件事:

  1. 它为此迁移创建一个新的 SQL 迁移文件
  2. 它针对数据库运行 SQL 迁移文件

该命令执行动作为:

  • 根据定义生成迁移文件
  • 执行新的迁移文件修改数据表
  • 生成 Prisma Client

②自动迁移

执行以下命令,将自动根据已经存在的数据库生成文件 prisman/schema.prisma ,而不需要向上面一样手动定义。

ruby 复制代码
$ npx prisma db pull

5.安装客户端

ruby 复制代码
$ npx prisma generate
  • 客户端提供众多方法完成对数据的增删改查
  • 你可以查看文档 prisma-client了解详细使用

6.更新表结构

使用 db push 来改变现有的原型架构,例如在某一个表中新增某个字段

perl 复制代码
$ npx prisma db push

7.重置数据库

如果你是使用自动迁移的方法导入映射关系,请确保你的数据留有备份,执行此操作在没有数据迁移记录的情况下,可能导致数据丢失。

通过运行以下命令自行 重置 数据库以撤消手动更改或 db push 的实验:

perl 复制代码
$ npx prisma migrate reset

该命令执行动作为:

  • 如果环境允许,则删除数据库;如果环境不允许删除数据库,则执行软重置。
  • 如果数据库被删除,则创建相同名称的新数据库。
  • 适用于所有迁移。
  • 运行种子脚本。

三、配置log日志输出

本文的配置环境是node18.18.1;prisma与@prisma/client的版本均为5.5.2

简单配置

在src目录下创建.env文件

在env文件中

ini 复制代码
#定义环境
NODE_ENV=development

在src目录下创建config.ts文件

markdown 复制代码
    //config.ts
    export default () => ({

      app: {

        name: 'MingxiangLuo',

        isDev: process.env.NODE_ENV == 'development',

      },

      database: {

        url: 'localhost',
    	
      },

    });

确保你的 prisma.module.ts 中有提供和导出PrismaService,例如:

kotlin 复制代码
    //prisma.module.ts
    import { Global, Module } from '@nestjs/common';

    import { PrismaService } from './prisma.service';

    @Global()

    @Module({

      providers: [PrismaService],

      exports: [PrismaService],

    })

    export class PrismaModule {}

prisma日志配置

官方在文档中做了如下说明:配置日志记录(概念)

创建 prisma.service.ts ,粘贴如下代码

prisma.service.ts 复制代码
    import { Injectable } from '@nestjs/common';
    import { ConfigService } from '@nestjs/config';
    import { PrismaClient } from '@prisma/client';

    @Injectable()
    export class PrismaService extends PrismaClient {
      constructor(configService: ConfigService) {
        //输出查询SQL等LOG
        super(
          configService.getOrThrow('app.isDev')
            ? { log: ['query', 'info', 'warn', 'error'] }
            : undefined,
        );
      }
    }

创建prisma.module.ts,粘贴如下代码

prisma.module.ts 复制代码
    import { Global, Module } from '@nestjs/common';
    import { PrismaService } from './prisma.service';

    @Global()
    @Module({
      providers: [PrismaService],
      exports: [PrismaService],
    })
    export class PrismaModule {}

在全局使用

在app.module.ts添加如下代码

app.module.ts 复制代码
import { Module } from '@nestjs/common';
import { PrismaModule } from '../prisma/prisma.module';
import { ConfigModule } from '@nestjs/config';
import config from './config';

@Module({
  imports: [
    PrismModule,
    ConfigModule.forRoot({
      isGlobal: true,
      load: [config],
    }),
  ],
  controllers: [],
  providers: [],

})

export class AppModule {}

在装饰器的构造函数中使用

*.controller.ts 复制代码
constructor(

    private readonly prisma: PrismaService,

  ) {}

基于事务配置

当我根据官方的文档配置时(stdout转成基于事件)出现了以下问题:

在on监听报错 类型"string"的参数不能赋给类型"never"的参数。ts(2345)

首先我在 stack overflow 中找到类似问题: typescript - Logging with Prisma 2 and NestJS - Dependency Injection problem? - Stack Overflow

但似乎不太能对我有帮助,于是我前往github prisma官方issues中找到答案,通过标签筛选出与 logging 有关的,我找到 issue#5026 与 issue#35

issue#5026: Printing full SQL queries with parameters in debug mode · Issue #5026 · prisma/prisma · GitHub

issue#35: How to access $on in PrismaService? · Issue #35 · notiz-dev/nestjs-prisma · GitHub

通过阅读各位大佬的回复,我发现这极有可能是本地ts语法检测有问题,于是我为报错的代码上一行添加 //@ts-ignore 这一句代码,即

typescript 复制代码
//prisma.service.ts
import { Injectable} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient {
  constructor(configService: ConfigService) {
    //输出查询SQL等LOG
    super(
      configService.getOrThrow('app.isDev')
        ? {
            log: [
              {
                emit: 'event',
                level: 'query' as const,
              },
              {
                emit: 'stdout',
                level: 'error',
              },
              {
                emit: 'stdout',
                level: 'info',
              },
              {
                emit: 'stdout',
                level: 'warn',
              },
            ],
          }
        : undefined,
    );

    //@ts-ignore
    this.$on('query', async (e) => {
      //@ts-ignore
      let timestamp = new Date();
      //@ts-ignore
      let query = e.query;
      //@ts-ignore
      let params = JSON.parse(e.params);
      //@ts-ignore
      let duration = e.duration;
      console.log({
        Timestamp: timestamp,
        Query: query,
        Params: params,
        Duration: duration,
      });
    });
  }
}

以上代码无报错提示,能够正常打印输出log日志

四、总结

本文为您介绍了如何在NestJS中使用Prisma以及配置prisma日志记录,希望通过本文的学习能够帮助您更好地使用NestJS搭建服务端。本文若有错误的地方,欢迎大家来互相交流鸭~

相关推荐
金銀銅鐵9 小时前
[Java] 用 GUI 展示 EnumSet 增减元素时的内部变化(上)
java·后端·ai编程
念何架构之路10 小时前
go-grpc设计思想
开发语言·后端·golang
system_error_x11 小时前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
步行cgn12 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
码事漫谈13 小时前
AI 读你的提示词,其实很没耐心
后端
用户83562907805114 小时前
如何使用 Python 格式化 Excel 单元格中的长文本
后端·python
我命由我1234514 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
IT_陈寒14 小时前
Java性能优化完全指南
前端·人工智能·后端
电子IT笔记14 小时前
对接群晖NAS,上传和删除踩坑记录
前端·后端
Mk5987814 小时前
P4:把 Agent 的记忆搬进 Redis —— AgentScope-Java 工程化实战
后端