@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 集成的关键。