我的 NestJS + Prisma 后端连接初体验

52 阅读4分钟

起因

最近在学习后端开发,听说 Prisma 这个 ORM 工具挺火的,就想着试试看。说实话,一开始真的是一头雾水,各种概念堆在一起,差点把我劝退了。

第一次接触 Prisma

按照教程执行 npx prisma init,竟然真的生成了两个文件!当时还挺兴奋的,原来 ORM 还能这么玩。不过看着那个 schema.prisma 文件,我心想:"这是什么鬼语法?"

Schema 文件让我困惑

prisma

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
}

这种语法真的很奇怪,不像 JavaScript,也不像 SQL。后来才明白,这是 Prisma 自己的 DSL(领域特定语言),专门用来描述数据库结构的。现在想想,这种设计其实挺好的,毕竟它要同时服务于 TypeScript 和 SQL。

数据库连接的心路历程

配置 .env 文件

env

DATABASE_URL="postgresql://username:password@localhost:5432/myapp"

说实话,第一次配置这个 URL 的时候,我把密码写错了好几次,每次连接都失败。后来发现 URL 里不能有特殊字符,还要做 URL 编码,真是踩了不少坑。

第一次成功连接

当我终于看到 prisma db pull 成功执行的时候,那种成就感真的难以言喻。虽然只是简单的命令,但意味着我终于和数据库建立了联系。

迁移过程的折腾

从 schema 到数据库

bash

npx prisma migrate dev --name init-user

这个命令我执行了好几遍才成功。第一次是因为数据库没启动,第二次是因为权限不够,第三次才成功。每次失败都在提醒我,后端开发真的容不得半点马虎。

DTO 验证的必要性

前端传参的混乱

刚开始我没有使用 DTO,直接在 Controller 里接收参数。结果前端同事随便传了个字符串给应该接收数字的字段,我的程序就崩溃了。那时候我才意识到验证的重要性。

发现 class-validator

ts

export class PostQueryDto {
  @IsNumber()
  @Min(1)
  page?: number = 1;
}

这个装饰器语法一开始看起来很奇怪,但是用起来真的很方便。特别是那个 @Min(1),直接避免了很多边界问题。

代码结构的思考

为什么要分这么多层?

最开始我很不理解为什么要分成 Controller、Service、Module 这么多层。直接在一个文件里写完不好吗?

后来在写一个稍微复杂的业务逻辑时,我发现如果所有代码都在 Controller 里,代码很快就变得一团糟。分开之后,每个部分职责清晰,修改起来也容易多了。

Service 层的作用

ts

async findAll(query: PostQueryDto) {
  const { page, limit, search } = query;
  const skip = (page - 1) * limit;
  
  // 这里是真正的业务逻辑
  return await this.prisma.post.findMany({
    skip,
    take: limit,
    where: search ? { title: { contains: search } } : {},
  });
}

把数据库操作放在这里,Controller 只负责接收和返回数据,确实让代码更清爽了。

遇到的坑和解决过程

1. 类型转换问题

ts

// URL 传过来的参数都是字符串
// page: "1" 需要转换成 number 1

这个问题困扰了我很久,直到发现了 transform: true 这个配置。现在想来,这其实是前端传参的常识,但当时确实卡住了。

2. 全局验证的配置

在 main.ts 里配置全局验证管道的时候,我试了好几种配置,最后选择了:

ts

app.useGlobalPipes(
  new ValidationPipe({
    whitelist: true,              // 过滤多余参数
    forbidNonWhitelisted: true,   // 遇到多余参数报错
    transform: true,              // 自动类型转换
  }),
)

这个配置让我在调试的时候少了很多麻烦,不会因为前端多传了一些参数而出现奇怪的问题。

实际使用感受

好的地方

  1. 智能提示很棒:定义好 Schema 后,写数据库操作代码时有完美的智能提示
  2. 类型安全:TypeScript 的类型推导真的很强大
  3. 调试友好:Prisma 会打印 SQL 语句,方便调试

不太习惯的地方

  1. 学习成本高:各种概念需要时间消化
  2. 配置复杂:相比直接写 SQL,配置步骤确实多一些
  3. 性能担忧:不知道在高并发情况下表现如何

总结

这次初体验让我对后端开发有了更深的认识。虽然过程有些曲折,但最终还是搭建好了基本的框架。Prisma 确实简化了很多数据库操作的复杂度,特别是类型安全这一点,真的是加分项。

当然,我也意识到自己还有很多不足,比如对数据库设计的理解还不够深入,对性能优化也没有太多经验。不过没关系,这些都是需要时间积累的。

下一步我想尝试加入用户认证和权限控制,看看能不能把这个基础框架做得更完善一些。毕竟,实践才是最好的学习方式。