在使用 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 的原因
-
数据丢失风险 :
- 当实体定义发生变化时(如删除字段、修改类型),TypeORM 会自动修改表结构
- 这可能导致现有数据被删除或类型转换错误,造成不可挽回的数据损失
-
性能问题 :
- 每次应用启动时,TypeORM 都会扫描所有实体并与数据库表结构进行比较
- 在大型应用中,这会显著增加启动时间,影响服务可用性
-
不可控性 :
- 自动同步可能会产生意外的表结构变更
- 无法预览或验证变更的影响,增加了生产环境的风险
-
版本控制缺失 :
- 自动同步的变更无法被版本控制系统跟踪
- 难以回滚错误的变更或查看变更历史
-
生产环境稳定性 :
- 生产环境需要严格的变更管理流程
- 数据库结构变更应该经过测试和审批,而不是自动执行
生产环境的替代方案
在生产环境中,应该使用 数据库迁移(Migrations) 来管理表结构变更:
-
创建迁移文件 :
pnpm run typeorm migration:create --name=CreateUsersTable -
编写迁移逻辑 :
// 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`); } } -
执行迁移 :
pnpm run typeorm migration:run -
回滚迁移 (如有必要):
pnpm run typeorm migration:revert