@nestjs/typeorm
是 NestJS 与 TypeORM 集成的官方模块,提供了 forRoot()
和 forFeature()
两个核心静态方法用于配置数据库连接和实体注册。本文将深入解析这两个方法的机制、使用场景和最佳实践。
一、TypeOrmModule.forRoot()
- 全局数据库配置
forRoot()
方法用于初始化全局数据库连接,通常在应用的根模块(如 AppModule
)中调用一次。
核心功能
- 创建数据库连接
- 配置全局选项(如实体扫描路径、迁移设置等)
- 注册为全局模块(可通过
@InjectConnection()
在任意地方注入)
基本用法
import { Module } from '@nestjs/common';
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 {}
高级配置选项
配置项 | 类型 | 说明 |
---|---|---|
type | 'mysql' | 'postgres' | 'sqlite' ... | 数据库类型 |
entities | (string | Function)[] | 实体类或扫描路径 |
synchronize | boolean | 自动同步实体结构(慎用) |
migrationsRun | boolean | 自动运行迁移 |
logging | boolean | ('query' | 'schema' | 'error' | 'warn' | 'info' | 'log')[] | SQL 日志 |
name | string | 多数据库连接时的名称标识 |
keepConnectionAlive | boolean | 应用关闭时保持连接 |
多数据库连接
TypeOrmModule.forRoot({name: 'secondary',type: 'postgres',// ...其他配置
});
二、TypeOrmModule.forFeature()
- 模块级实体注册
forFeature()
方法用于在特定模块中注册实体和自定义 Repository,使它们仅在该模块的作用域内可用。
核心功能
- 注册实体(使它们可用于当前模块的 Repository)
- 注册自定义 Repository
- 支持多数据库连接(通过
connectionName
指定)
基本用法
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserEntity } from './user.entity';
import { UserRepository } from './user.repository';@Module({imports: [TypeOrmModule.forFeature([UserEntity, UserRepository]),],
})
export class UserModule {}
关键特性解析
1. 实体注册机制
- 自动注入依赖:注册的实体可通过
@InjectRepository()
在服务中使用 - 作用域隔离:实体仅在当前模块可用(除非全局注册)
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { UserEntity } from './user.entity';@Injectable()
export class UserService {constructor(@InjectRepository(UserEntity)private userRepository: Repository<UserEntity>) {}
}
2. 自定义 Repository 支持
// user.repository.ts
import { EntityRepository, Repository } from 'typeorm';
import { UserEntity } from './user.entity';@EntityRepository(UserEntity)
export class UserRepository extends Repository<UserEntity> {findByName(name: string) {return this.findOne({ where: { name } });}
}// user.module.ts
TypeOrmModule.forFeature([UserRepository]); // 必须注册自定义 Repository
3. 多数据库连接支持
TypeOrmModule.forFeature([UserEntity], 'secondary' // 指定连接名称
);
三、forRoot
与 forFeature
的协作机制
1. 初始化流程
- 应用启动时,
forRoot()
创建全局数据库连接 - 模块加载时,
forFeature()
从全局连接中提取指定实体 - 动态生成包含实体和 Repository 的子模块
2. 依赖注入关系
forRoot()
注册的连接可通过@InjectConnection()
获取forFeature()
注册的 Repository 可通过@InjectRepository()
获取
import { Injectable } from '@nestjs/common';
import { InjectConnection, InjectRepository } from '@nestjs/typeorm';
import { Connection, Repository } from 'typeorm';
import { UserEntity } from './user.entity';@Injectable()
export class DatabaseService {constructor(@InjectConnection() private connection: Connection,@InjectRepository(UserEntity) private userRepository: Repository<UserEntity>) {}
}
四、高级使用场景
1. 动态实体注册
const entities = [UserEntity, ProductEntity]; // 可动态生成
TypeOrmModule.forFeature(entities);
2. 测试环境配置
TypeOrmModule.forRoot({type: 'sqlite',database: ':memory:',entities: [UserEntity],synchronize: true,
});
3. 混合使用全局和局部实体
// app.module.ts
TypeOrmModule.forRoot({entities: [SharedEntity], // 全局实体
});// feature.module.ts
TypeOrmModule.forFeature([LocalEntity]); // 局部实体
五、常见问题解决方案
1. RepositoryNotFoundError
- 原因:未在
forFeature()
中注册实体 - 解决:确保使用实体的模块已正确注册
2. 多数据库连接冲突
- 原因:未指定
connectionName
- 解决:
// 注册时指定名称 TypeOrmModule.forRoot({ name: 'secondary', ... });// 使用时指定连接 TypeOrmModule.forFeature([Entity], 'secondary');
3. 性能优化技巧
- 避免全局扫描:显式指定实体而非使用通配符
// 不推荐(生产环境) entities: [__dirname + '/**/*.entity{.ts,.js}']// 推荐 entities: [UserEntity, ProductEntity]
六、最佳实践总结
场景 | 推荐方案 |
---|---|
单数据库应用 | 在根模块使用一次 forRoot() ,按需在功能模块使用 forFeature() |
多数据库连接 | 为每个连接配置唯一的 name ,使用时显式指定 |
自定义 Repository | 必须通过 forFeature() 注册 |
测试环境 | 使用内存数据库(如 SQLite) |
生产环境 | 禁用 synchronize ,使用迁移 |
七、完整示例
// app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserModule } from './user/user.module';@Module({imports: [TypeOrmModule.forRoot({type: 'postgres',host: 'localhost',port: 5432,username: 'postgres',password: 'postgres',database: 'main',entities: [__dirname + '/**/*.entity{.ts,.js}'],synchronize: false,migrationsRun: true,migrations: [__dirname + '/migrations/**/*{.ts,.js}'],}),UserModule,],
})
export class AppModule {}// user.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserEntity } from './user.entity';
import { UserService } from './user.service';
import { UserRepository } from './user.repository';@Module({imports: [TypeOrmModule.forFeature([UserEntity, UserRepository]),],providers: [UserService],exports: [UserService],
})
export class UserModule {}
通过合理使用 forRoot
和 forFeature
,可以构建出既灵活又高效的数据库访问层架构。理解这两个方法的协作机制是掌握 NestJS + TypeORM 集成的关键。