FORMA

数据库集成(以 TypeORM 为例)

Nest 通过 @nestjs/typeorm 等包集成 ORM;生产环境用 migration,慎用 synchronize。亦可选用 Prisma、MikroORM 等(见 官方 Database)。

下文以 @nestjs/typeorm + TypeORM 为例(支持 MySQL、PostgreSQL、SQLite 等)。

一、@nestjs/typeorm 模块

安装依赖:

bash
npm install @nestjs/typeorm typeorm mysql2   # 以 MySQL 为例

该模块导出了 TypeOrmModule,它提供了:

  • forRoot() / forRootAsync():配置数据库连接(应用级别配置)。
  • forFeature():在特定模块中注册实体仓库(Repository),以便注入使用。

二、配置(TypeOrmModule.forRoot()forRootAsync

1. 同步配置(forRoot

直接在根模块(如 AppModule)中调用,传入配置对象。

ts
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { User } from "./users/user.entity";

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: "mysql",
      host: "localhost",
      port: 3306,
      username: "root",
      password: "password",
      database: "test",
      entities: [User], // 自动加载实体
      synchronize: true, // 生产环境应设为 false,使用 migration
      logging: true,
    }),
  ],
})
export class AppModule {}

关键配置项

  • type:数据库类型(mysqlpostgressqlite 等)。
  • hostportusernamepassworddatabase:连接参数。
  • entities:实体类列表(或使用 autoLoadEntities: true 自动加载)。
  • synchronize:自动同步实体结构到数据库(仅开发/测试环境)。
  • logging:打印 SQL 日志。

2. 异步配置(forRootAsync

适合从环境变量或配置服务动态加载配置。支持 useFactoryuseClassuseExisting

ts
TypeOrmModule.forRootAsync({
  imports: [ConfigModule],
  useFactory: (configService: ConfigService) => ({
    type: "mysql",
    host: configService.get("DB_HOST"),
    port: +configService.get("DB_PORT"),
    username: configService.get("DB_USER"),
    password: configService.get("DB_PASSWORD"),
    database: configService.get("DB_NAME"),
    entities: [User], // 或 autoLoadEntities: true
    synchronize: configService.get("NODE_ENV") !== "production",
  }),
  inject: [ConfigService],
});

也可以使用 useClass 指定一个自定义配置工厂类。

三、实体(Entity)

实体是映射到数据库表的一个类。使用 @Entity() 装饰器声明,字段用 @Column()@PrimaryGeneratedColumn() 等修饰。

ts
// user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from "typeorm";

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

  @Column({ length: 100 })
  name: string;

  @Column({ unique: true })
  email: string;

  @Column({ default: true })
  isActive: boolean;
}

常用装饰器

  • @PrimaryGeneratedColumn():自增主键。
  • @Column():普通列,可传选项(长度、默认值、唯一等)。
  • @CreateDateColumn() / @UpdateDateColumn():自动填充时间戳。
  • @Index():为字段创建索引。

四、Repository 模式

Repository 是操作数据库的核心接口,提供 findsavedelete 等方法。

1. 注册 Repository

在模块中使用 TypeOrmModule.forFeature() 注册实体,这样 NestJS 的 DI 容器就会提供对应的 Repository。

ts
// users.module.ts
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { User } from "./user.entity";
import { UsersService } from "./users.service";
import { UsersController } from "./users.controller";

@Module({
  imports: [TypeOrmModule.forFeature([User])], // 注册 User 仓库
  providers: [UsersService],
  controllers: [UsersController],
})
export class UsersModule {}

2. 注入 Repository

在 Service 中通过 @InjectRepository() 注入特定实体的 Repository。

ts
// users.service.ts
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { User } from "./user.entity";

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

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

  findOne(id: number): Promise<User | null> {
    return this.usersRepository.findOneBy({ id });
  }

  async create(userData: Partial<User>): Promise<User> {
    const newUser = this.usersRepository.create(userData);
    return this.usersRepository.save(newUser);
  }

  async remove(id: number): Promise<void> {
    await this.usersRepository.delete(id);
  }
}

五、关系(Relationships)

TypeORM 支持常见的关系映射,通过装饰器声明。

关系装饰器示例
一对多@OneToMany + @ManyToOneUserPost
一对一@OneToOneUserProfile
多对多@ManyToMany + @JoinTableUserRole

示例:User 与 Post 的一对多关系

ts
// user.entity.ts
import { OneToMany } from "typeorm";
import { Post } from "./post.entity";

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

  @OneToMany(() => Post, (post) => post.user)
  posts: Post[];
}

// post.entity.ts
@Entity()
export class Post {
  @PrimaryGeneratedColumn()
  id: number;

  @ManyToOne(() => User, (user) => user.posts)
  user: User;
}

查询时使用 relations 选项加载关联:

ts
const user = await this.usersRepository.findOne({
  where: { id: 1 },
  relations: ["posts"],
});

六、事务(Transaction)

TypeORM 提供多种事务方式,NestJS 推荐使用 QueryRunner 进行显式事务控制。

ts
import { Injectable } from "@nestjs/common";
import { InjectDataSource } from "@nestjs/typeorm";
import { DataSource } from "typeorm";

@Injectable()
export class OrderService {
  constructor(@InjectDataSource() private dataSource: DataSource) {}

  async createOrderWithItems() {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 使用 queryRunner.manager 进行数据库操作
      const order = await queryRunner.manager.save(Order, { userId: 1 });
      const item = await queryRunner.manager.save(OrderItem, { orderId: order.id });

      await queryRunner.commitTransaction();
      return { order, item };
    } catch (err) {
      await queryRunner.rollbackTransaction();
      throw err;
    } finally {
      await queryRunner.release();
    }
  }
}

注意@Transaction@TransactionManager 装饰器已过时,推荐使用 QueryRunner 方式。

七、其他 ORM / ODM

1. Sequelize (@nestjs/sequelize)

Sequelize 是另一个流行的 Node.js ORM,支持 PostgreSQL、MySQL 等。

ts
import { SequelizeModule } from "@nestjs/sequelize";

@Module({
  imports: [
    SequelizeModule.forRoot({
      dialect: "mysql",
      host: "localhost",
      port: 3306,
      username: "root",
      password: "password",
      database: "test",
      models: [User],
    }),
    SequelizeModule.forFeature([User]), // 注册模型
  ],
})
export class AppModule {}

在 Service 中注入模型:

ts
@Injectable()
export class UsersService {
  constructor(@InjectModel(User) private userModel: typeof User) {}
  async findAll() {
    return this.userModel.findAll();
  }
}

2. Mongoose (@nestjs/mongoose)

用于 MongoDB 数据库,基于 Mongoose ODM。

ts
import { MongooseModule } from "@nestjs/mongoose";

@Module({
  imports: [
    MongooseModule.forRoot("mongodb://localhost:27017/nest"),
    MongooseModule.forFeature([{ name: "Cat", schema: CatSchema }]),
  ],
})
export class AppModule {}

Service 中使用 @InjectModel() 注入 Model。

3. Prisma(手动集成)

Prisma 是新一代 TypeScript ORM,需要手动安装 @prisma/client 并生成客户端。

ts
// 1. 安装并初始化
npm install @prisma/client
npx prisma init

// 2. 定义 schema(prisma/schema.prisma)
model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  name  String
}

// 3. 生成客户端
npx prisma generate

在 NestJS 中创建 Prisma 服务:

ts
import { Injectable, OnModuleInit } from "@nestjs/common";
import { PrismaClient } from "@prisma/client";

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }
}

然后在其他服务中注入 PrismaService,调用其生成的方法(如 prisma.user.findMany())。

总结

功能TypeORM 方式
模块配置TypeOrmModule.forRoot / forRootAsync
注册仓库TypeOrmModule.forFeature
注入仓库@InjectRepository(Entity)
实体定义@Entity()@Column()
关系@OneToMany@ManyToOne
事务QueryRunner 显式控制
异步配置useFactory + 注入配置服务

选择 ORM 时,关系型数据库优先 TypeORM 或 Sequelize,MongoDB 使用 Mongoose,追求类型安全和简洁可考虑 Prisma。NestJS 的数据库集成非常灵活,可根据项目需求选择合适的技术栈。

参考文献

以下链接在编写时均可正常访问:

资料说明
NestJS 文档官方
Database本章主题
Request lifecycle执行顺序

Series

new

8 / 19