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.entitiesDir 和 cli.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
相关推荐
孟陬18 小时前
解决动态 import 类型 Any 痼癖
typescript·node.js·bun
Dumbness18 小时前
后台管理员把自己锁在门外:RBAC 里「自己的权限只能由别人来减」
安全·node.js
攻城狮白玉20 小时前
Node.js 发布紧急安全更新:10 个漏洞,8 枚危险证书被拉黑。附AI修复提示词
node.js
Json____1 天前
用 FastAPI + Vue3 打造一套完整的在线考试系统:从组卷到阅卷的业务闭环实践
后端·node.js·fastapi·it学习·wwwoop.com
Dumbness2 天前
写 MCP 服务器踩的坑:stdout 是协议通道,一行不带换行的日志就能让客户端超时
node.js·mcp
flash俊杰2 天前
ContentPart 联合类型实战:不碰存量消息,怎么给 ChatMessage 加图片
node.js
Json____2 天前
用 Node.js + Vue3 打造一个家居装修 AI 智能咨询助手
node.js·agent·网站开发·智能体·wwwoop.com
幸运小圣2 天前
fs 模块完全指南:文件读写、移动删除与文件夹操作(新手友好)【Node.js】
node.js·编辑器·vim
Dumbness3 天前
不发 npm 也能 npx:用 github: 协议分发一个零依赖 CLI
node.js
Patrick_Wilson3 天前
npm 的 bin 如何接到 npm run 与 npx
npm·node.js·前端工程化