「项目实战」从0搭建NestJS后端服务(二):数据库选型和Prisma整合

前言

大家好,我是elk。之前学习NestJS时一直用TypeORM,但最近发现Prisma这个宝藏ORM框架,论坛里都在说它更香!这次就带大家用实战体验一把NestJS+Prisma组合拳,手把手教你们从零搭建用户模块。

(小声BB:官方文档虽然好,但有些坑还得自己踩过才懂)

🗃️ 数据库选型:MySQL vs PostgreSQL

一句话对比指南

  • MySQL:适合快速开发,团队熟悉传统关系型数据库
  • PostgreSQL:适合处理复杂查询、地理位置数据,自带Buff加成

举个栗子🌰:

  • 用户管理系统 → 选MySQL
  • 外卖配送系统(需要地理坐标) → 选PostgreSQL

这次咱们先用MySQL演示,毕竟大多数项目都从这里起步~

Prisma初始化

prisma插件

bash 复制代码
# 安装核心工具
pnpm install prisma --save-dev

初始化prisma配置

csharp 复制代码
# 初始化配置文件
pnpm prisma init

此时项目根目录创建了一个prisma目录和一个.env文件,里面有一个schema.prisma

  • schema.prisma :指定数据库连接并包含数据库schema
  • .envdotenv文件,通常用于将数据库凭据存储在一组环境变量中

安装prisma客户端

为了能够在Nest应用中与数据库进行交互,需要客户端

bash 复制代码
# 安装客户端(重要!)
pnpm install @prisma/client

配置连接数据库

  • schema.prisma
ini 复制代码
// 定义生成器,指定使用 Prisma Client JS 作为生成的客户端代码
generator client {
  // 生成器的提供者,这里使用 Prisma Client JS
  provider = "prisma-client-js"
}
​
// 定义数据源,指定数据库的相关信息
datasource db {
  // 数据源的提供者,这里使用 MySQL 数据库
  provider = "mysql"
  // 数据库连接的 URL,从环境变量中获取
  url      = env("DATABASE_URL")
}
  • .env
ini 复制代码
# 配置 MySQL 数据库的连接地址,Prisma 将使用该地址连接到数据库
# 数据库的用户名是 root,密码是 123456
# 数据库运行在本地主机上,端口号是 33061
# 要连接的数据库名称是 elk_db
DATABASE_URL="mysql://root:123456@localhost:33061/elk_db"

创建sty_user表

  • Schema.prisma
typescript 复制代码
// 定义生成器,指定使用 Prisma Client JS 作为生成的客户端代码
generator client {
  // 生成器的提供者,这里使用 Prisma Client JS
  provider = "prisma-client-js"
}
​
// 定义数据源,指定数据库的相关信息
datasource db {
  // 数据源的提供者,这里使用 MySQL 数据库
  provider = "mysql"
  // 数据库连接的 URL,从环境变量中获取
  url      = env("DATABASE_URL")
}
​
// 用户表
model sys_user {
  userid    BigInt   @id @default(autoincrement())
  deptid    BigInt
  username  String   @unique
  nickname  String
  email     String   @unique
  phone     String   @unique
  sex       String   @default("0")
  avatar    String
  status    String   @default("0")
  remark    String
  password  String
  createdBy String
  updatedBy String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

pack.json新增命令

json 复制代码
"scripts": {
  "prisma:pull-DB": "prisma db pull",
  "prisma:push-DB": "prisma db push",
  "prisma:migrate-create": "prisma migrate dev --name init"
}
  • prisma db pull:用与开发环境中,将数据库的表设定,同步到项目中
  • prisma db push:用于开发环境中,将项目中表定义的改动,同步到数据库中
  • prisma migrate dev --name init:用于开发环境中,将项目中表定义的改动,同步到数据库中,并在项目中生成一条操作记录「数据库迁移,初始化」

执行命令,初始化库

bash 复制代码
# 在项目终端使用
pnpm prisma:migrate-create

执行完之后,prisma生成一个migrations目录,存放对应的SQL文件

使用vscode中的一个插件 database插件去查看库里是否建立了sty_user表

nest中使用prisma

arduino 复制代码
# 生成专门的module、service文件
# prisma目录下
nest g mo prisma
nest g s prisma
  • prisma.module.ts
kotlin 复制代码
import { Module, Global } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Global()
@Module({
  providers: [PrismaService],
  exports: [PrismaService],
})
export class PrismaModule {}
  • prisma.service.ts
typescript 复制代码
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    // 调用 PrismaClient 的 $connect 方法,连接到数据库
    await this.$connect();
  }
  // 关闭连接
  async enableShutdownHooks(app: INestApplication) {
    // 监听 Prisma 客户端的 'beforeExit' 事件
    this.$on('beforeExit', async () => {
      // 调用 NestJS 应用程序的 close 方法,关闭应用程序
      await app.close();
    });
  }
}

user模块调用

bash 复制代码
# 生成一套CRUD模版
nest g res user
  • user.moduel.ts
typescript 复制代码
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';

// 引入prisma服务
import { PrismaService } from '../../prisma/prisma.service';

@Module({
  controllers: [UserController],
  providers: [UserService, PrismaService],
})
export class UserModule {}
  • user.service.ts
typescript 复制代码
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

// 引入prisma服务
import { PrismaService } from '../../prisma/prisma.service';

@Injectable()
export class UserService {
  // 注入prisma服务
  constructor(private prisma: PrismaService) {}
  create(createUserDto: CreateUserDto) {
    return 'This action adds a new user';
  }

  async findAll() {
    // 查询用户表
    const user = await this.prisma.sys_user.findMany();
    console.log('🚀 ~ UserService ~ findAll ~ user:', user);
    return `This action returns all user`;
  }

  findOne(id: number) {
    return `This action returns a #${id} user`;
  }

  update(id: number, updateUserDto: UpdateUserDto) {
    return `This action updates a #${id} user`;
  }

  remove(id: number) {
    return `This action removes a #${id} user`;
  }
}

📍 下期预告

《从0搭建NestJS后端服务(三):环境配置以及CORS处理》

我们将探讨:

  • 如何优雅管理多环境配置
  • 跨域问题的三种解决姿势
  • 接口突然挂了的应急方案

🤝 互动时间

新手村同学 :卡在哪一步了?评论区说出你的血泪史!
满级大佬:你们团队怎么处理数据库迁移?求分享最佳实践!

欢迎在评论区分享你的实战经验!

相关推荐
晓夜残歌21 分钟前
安全基线-rm命令防护
运维·服务器·前端·chrome·安全·ubuntu
inxunoffice1 小时前
批量删除 PPT 空白幻灯片页面
前端·powerpoint
Setsuna_F_Seiei3 小时前
前端切图仔的一次不务正业游戏开发之旅
前端·游戏·cocos creator
laimaxgg3 小时前
Qt窗口控件之颜色对话框QColorDialog
开发语言·前端·c++·qt·命令模式·qt6.3
爱编程的鱼3 小时前
Unity—从入门到精通(第一天)
前端·unity·ue5·游戏引擎
默默无闻 静静学习3 小时前
sass介绍
前端·sass
大怪v4 小时前
前端佬们,装起来!给设计模式【祛魅】
前端·javascript·设计模式
MetaverseMan4 小时前
Rust Tokio 和 Node.js 异步的相似之处
开发语言·rust·node.js
vvilkim4 小时前
Vue.js 插槽(Slot)详解:让组件更灵活、更强大
前端·javascript·vue.js
学无止境鸭4 小时前
uniapp报错 Right-hand side of ‘instanceof‘ is not an object
前端·javascript·uni-app