NestJS 实战:TypeORM 从入门到精通(完整教程)

在使用 NestJS 开发后端服务时,数据库操作是必不可少的环节。

TypeORM 是一个功能强大的 ORM 框架,完美支持 TypeScript,并且与 NestJS 深度集成,是官方首选的数据访问解决方案。

本篇文章带你从 0 到 1 掌握 NestJS + TypeORM,包含配置、实体定义、CRUD、事务、数据库迁移等企业级实战内容。

TypeORM 简介

ypeORM 是 Object-Relational Mapping(对象关系映射) 库,用于将 JavaScript/TypeScript 对象映射到数据库表结构,让我们可以用面向对象的方式操作数据库,不用手写大量 SQL 语句。

支持数据库:

● MySQL、PostgreSQL、SQLite

● SQL Server、Oracle

● MongoDB(NoSQL)

核心特性

● ✅ 支持 TypeScript 装饰器语法

● ✅ 支持 Active Record / Data Mapper 模式

● ✅ 自动同步表结构(开发环境)

● ✅ 强大的查询构建器

● ✅ 支持事务、迁移、关联查询

● ✅ 与 NestJS 无缝集成

安装依赖

确保已安装 NestJS 和 TypeORM 核心包:

bash 复制代码
npm install @nestjs/typeorm typeorm mysql2

根据使用的数据库选择对应的驱动(如 PostgreSQL 使用 pg)。

配置 TypeORM 模块

在 NestJS 应用的主模块中导入 TypeOrmModule 并配置数据库连接:

typescript 复制代码
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'password',
      database: 'test',
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true,
    }),
  ],
})
export class AppModule {}

创建实体

定义 TypeORM 实体类,使用装饰器标记字段和关系,通过装饰器定义数据库表结构:

typescript 复制代码
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

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

  @Column()
  name: string;

  @Column()
  email: string;
}

注册实体与仓库

在特性模块中通过 TypeOrmModule.forFeature() 注册实体,自动生成 Repository:

typescript 复制代码
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';

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

使用 Repository

通过依赖注入在服务层使用 Repository:

typescript 复制代码
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

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

  findAll(): Promise<User[]> {
    return this.userRepository.find();
  }
}

事务管理

使用 @Transaction@TransactionManager 装饰器管理事务:

typescript 复制代码
import { Transaction, TransactionManager } from 'typeorm';

async createUser(userData: Partial<User>) {
  return this.userRepository.manager.transaction(async manager => {
    const user = manager.create(User, userData);
    return manager.save(user);
  });
}

迁移与 CLI

TypeORM 提供命令行工具生成和管理迁移:

bash 复制代码
typeorm migration:create -n UserMigration
typeorm migration:run

在 NestJS 中可通过配置 cli.entitiesDircli.migrationsDir 路径。

高级特性

  • 多数据库连接 :通过 TypeOrmModule.forRoot()name 属性支持多连接
  • 订阅者 :实现 EntitySubscriberInterface 监听实体事件
  • 查询构建器 :使用 createQueryBuilder() 进行复杂查询

通过以上步骤,可在 NestJS 应用中高效集成 TypeORM,实现完整的数据访问层。注意生产环境应关闭 synchronize 选项,改用迁移管理数据库结构变更。

synchronize 使用解析

在 TypeORM 中, synchronize: true 选项的作用是在应用启动时自动同步实体定义和数据库表结构。虽然这个选项在开发阶段非常方便,但在生产环境中必须关闭,主要原因如下:

生产环境关闭 synchronize: true 的原因

  1. 数据丢失风险 :

    • 当实体定义发生变化时(如删除字段、修改类型),TypeORM 会自动修改表结构
    • 这可能导致现有数据被删除或类型转换错误,造成不可挽回的数据损失
  2. 性能问题 :

    • 每次应用启动时,TypeORM 都会扫描所有实体并与数据库表结构进行比较
    • 在大型应用中,这会显著增加启动时间,影响服务可用性
  3. 不可控性 :

    • 自动同步可能会产生意外的表结构变更
    • 无法预览或验证变更的影响,增加了生产环境的风险
  4. 版本控制缺失 :

    • 自动同步的变更无法被版本控制系统跟踪
    • 难以回滚错误的变更或查看变更历史
  5. 生产环境稳定性 :

    • 生产环境需要严格的变更管理流程
    • 数据库结构变更应该经过测试和审批,而不是自动执行

生产环境的替代方案

在生产环境中,应该使用 数据库迁移(Migrations) 来管理表结构变更:

  1. 创建迁移文件 :

    复制代码
    pnpm run typeorm migration:create 
    --name=CreateUsersTable
  2. 编写迁移逻辑 :

    复制代码
    // migrations/
    1620000000000-CreateUsersTable.ts
    import { MigrationInterface, 
    QueryRunner } from 'typeorm';
    
    export class 
    CreateUsersTable1620000000000 
    implements MigrationInterface {
      public async up(queryRunner: 
      QueryRunner): Promise<void> {
        await queryRunner.query(`
          CREATE TABLE users (
            id INT PRIMARY KEY 
            AUTO_INCREMENT,
            name VARCHAR(255) NOT NULL,
            email VARCHAR(255) UNIQUE NOT 
            NULL
          )
        `);
      }
    
      public async down(queryRunner: 
      QueryRunner): Promise<void> {
        await queryRunner.query(`DROP TABLE 
        users`);
      }
    }
  3. 执行迁移 :

    复制代码
    pnpm run typeorm migration:run
  4. 回滚迁移 (如有必要):

    复制代码
    pnpm run typeorm migration:revert
相关推荐
太难了啊3 小时前
5分钟实现你的第一个 Node.js 智能体
人工智能·node.js
MingT 明天你好!4 小时前
trae中安装mcp报Cannot find package/ERR_MODULE_NOT_FOUND问题
node.js·trae
米丘8 小时前
从 HTTP 到 WebSocket:深入 Vite HMR 的网络层原理
http·node.js·vite
米丘8 小时前
Node.js 事件循环
前端·javascript·node.js
Kel8 小时前
深入 Ink 源码:当 React 遇见终端 —— Custom Reconciler 全链路剖析
react.js·架构·node.js
全马必破三10 小时前
Vue3+Node.js 实现AI流式输出全解析
前端·javascript·node.js
吴声子夜歌11 小时前
Node.js——util工具模块
node.js
笑笑先生12 小时前
从接口搬运工到研发控制平面,BFF 到底在解决什么?
前端·架构·node.js
www_stdio12 小时前
🚀 从 Event Loop 到 AI Agent:我的 Node.js 全栈进阶之路
前端·node.js·nestjs