数据库操作:mysql2(直接 SQL) vs TypeORM(ORM 方式)


数据库操作:mysql2(直接 SQL) vs TypeORM(ORM 方式)

大家好,今天我们来聊聊 Node.js 后端开发中的核心话题——数据库操作。在 NestJS 框架里,我们操作数据库主要有两种方式:一种是直接用 SQL 驱动(比如 mysql2)发送原生 SQL 语句,另一种是使用 ORM(对象关系映射)框架,比如 TypeORM,通过类和装饰器来映射数据库表。这两种方式各有千秋,今天我们就来详细对比一下,帮你根据项目需求做出选择。


一、文件里的原话

先回顾一下文件里是怎么说的:

Node 里操作数据库的两种方式:
一种是直接用 mysql2 连接数据库,发送 sql 来执行。
一种是用 ORM 库,比如 typeorm,它是基于 class 和 class 上的装饰器来声明和表的映射关系的,然后对表的增删改查就变成了对象的操作以及 save、find 等方法的调用。它会自动生成对应的 sql。

这段话非常精炼地概括了两种方式的核心区别。下面我们展开细说。


二、方式一:直接用 mysql2 发送 SQL

是什么?

mysql2 是 Node.js 中一个流行的 MySQL 客户端驱动,它是 mysql 包的升级版,支持 Promise、预处理语句等现代特性。用 mysql2 操作数据库,你需要自己写 SQL 语句,自己处理结果集,自己管理连接池。

在 NestJS 中怎么用?

你可以创建一个服务,封装数据库连接和查询方法。例如:

import { Injectable } from '@nestjs/common';
import * as mysql from 'mysql2/promise';

@Injectable()
export class DatabaseService {
  private pool;

  constructor() {
    this.pool = mysql.createPool({
      host: 'localhost',
      user: 'root',
      password: 'password',
      database: 'test',
      waitForConnections: true,
      connectionLimit: 10,
    });
  }

  async query(sql: string, params?: any[]) {
    const [rows] = await this.pool.execute(sql, params);
    return rows;
  }
}

然后在你的服务里注入 DatabaseService,直接调用 query 方法执行 SQL:

@Injectable()
export class UserService {
  constructor(private db: DatabaseService) {}

  async findOne(id: number) {
    const rows = await this.db.query('SELECT * FROM users WHERE id = ?', [id]);
    return rows[0];
  }
}

优点

  • 完全控制:你写什么 SQL,数据库就执行什么 SQL,没有中间层帮你“翻译”,性能最高。
  • 学习曲线低:如果你已经熟悉 SQL,上手极快,不需要学习 ORM 的规则。
  • 适合复杂查询:对于多表关联、子查询、窗口函数等复杂 SQL,原生 SQL 写起来更直接。
  • 轻量:不需要额外的 ORM 依赖,项目更轻。

缺点

  • 手动映射:查询结果返回的是普通的 JavaScript 对象,你需要手动把它转换成业务对象,或者手动处理关系。
  • 类型安全差:TypeScript 类型需要自己定义,容易出错。
  • 重复代码:每个查询都要写 SQL,表名、字段名硬编码,容易写错且难以维护。
  • 数据库迁移麻烦:表结构变更需要手动维护 SQL 脚本。

三、方式二:使用 TypeORM(ORM 框架)

是什么?

TypeORM 是一个 TypeScript 友好的 ORM 框架,它让你用类和装饰器来定义实体(Entity),每个实体对应数据库中的一张表。然后你就可以通过 Repository 提供的 API 进行 CRUD 操作,而不需要写 SQL。

在 NestJS 中怎么用?

Nest 官方提供了 @nestjs/typeorm 包,可以无缝集成 TypeORM。

首先安装依赖:

npm install @nestjs/typeorm typeorm mysql2

然后在 AppModule 中配置连接:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'password',
      database: 'test',
      entities: [User],
      synchronize: true, // 开发环境自动建表,生产环境建议关闭
    }),
  ],
})
export class AppModule {}

定义一个实体类:

import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  age: number;
}

在模块中引入实体的 Repository:

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  providers: [UserService],
})
export class UserModule {}

然后在服务里注入 Repository 进行操作:

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
  ) {}

  async findOne(id: number) {
    return this.userRepository.findOne({ where: { id } });
  }

  async create(data: Partial<User>) {
    const user = this.userRepository.create(data);
    return this.userRepository.save(user);
  }
}

优点

  • 开发效率高:不用写 SQL,所有操作通过方法调用完成,代码量少。
  • 类型安全:实体类就是 TypeScript 类,字段类型明确,IDE 自动提示。
  • 关系映射方便:可以用 @OneToMany@ManyToOne 等装饰器定义表关系,查询时自动关联。
  • 迁移工具:TypeORM 提供了 CLI 工具,可以根据实体变化生成迁移脚本,方便版本控制。
  • 数据库无关:切换数据库(比如从 MySQL 换到 PostgreSQL)只需要改配置,代码几乎不用动。

缺点

  • 学习曲线:需要学习 TypeORM 的 API 和装饰器,理解它的工作原理。
  • 性能开销:ORM 会做一些额外的操作,比如解析实体、生成 SQL,比原生 SQL 稍慢,但对于大多数应用来说可以忽略。
  • 复杂查询不够直观:对于非常复杂的 SQL,用 ORM 的方法链可能会变得晦涩难懂,不如直接写 SQL。
  • 灵活性受限:有些数据库特性 ORM 可能不支持,需要回退到原生查询。

四、如何选择?

其实没有绝对的好坏,主要看你的项目场景和团队偏好。

  • 如果你喜欢完全掌控,SQL 功底扎实,或者项目中有大量复杂查询,直接用 mysql2 会更灵活。
  • 如果你追求开发效率,希望代码更易于维护,团队有 TypeScript 规范,TypeORM 是更好的选择。
  • 混合使用:即使用了 TypeORM,遇到复杂查询也可以通过 createQueryBuilder 或者直接执行原生 SQL,两种方式可以并存。Nest 里你可以同时使用 TypeORM 和原生查询。

文件里也提到两种方式,没有偏向哪一种,只是客观介绍。在实际 Nest 项目中,官方推荐 TypeORM 因为集成度高,但如果你有特殊需求,完全可以用 mysql2 自己封装。


五、总结

无论是用 mysql2 直接写 SQL,还是用 TypeORM 操作实体,都是 Node.js 操作 MySQL 的成熟方案。mysql2 给你自由,TypeORM 给你效率。在 NestJS 里,你可以根据项目阶段和复杂度灵活选择,甚至两者结合使用。关键是理解它们的适用场景,做出最适合项目的决策。

声明:麋鹿与鲸鱼|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 数据库操作:mysql2(直接 SQL) vs TypeORM(ORM 方式)


Carpe Diem and Do what I like