数据库集成概述
NestJS 提供了对多种数据库的完整支持,包括关系型数据库(如 MySQL、PostgreSQL)和非关系型数据库(如 MongoDB)。通过使用 TypeORM、Prisma、Mongoose 等 ORM/ODM 库,开发者可以轻松实现数据库操作。
TypeORM 集成
安装依赖
bashnpm install @nestjs/typeorm typeorm npm install mysql2 # 或 pg、sqlite3、better-sqlite3 等
配置 TypeORM
typescriptimport { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { User } from './entities/user.entity'; @Module({ imports: [ TypeOrmModule.forRoot({ type: 'mysql', host: 'localhost', port: 3306, username: 'root', password: 'password', database: 'test', entities: [User], synchronize: true, // 生产环境应设为 false logging: true, }), TypeOrmModule.forFeature([User]), ], providers: [UserService], controllers: [UserController], }) export class UserModule {}
创建实体
typescriptimport { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm'; @Entity('users') export class User { @PrimaryGeneratedColumn() id: number; @Column({ unique: true }) email: string; @Column() password: string; @Column() name: string; @Column({ default: true }) isActive: boolean; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; }
创建 Repository
typescriptimport { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { User } from './entities/user.entity'; import { CreateUserDto } from './dto/create-user.dto'; @Injectable() export class UserService { constructor( @InjectRepository(User) private userRepository: Repository<User>, ) {} async create(createUserDto: CreateUserDto): Promise<User> { const user = this.userRepository.create(createUserDto); return this.userRepository.save(user); } async findAll(): Promise<User[]> { return this.userRepository.find(); } async findOne(id: number): Promise<User> { return this.userRepository.findOne({ where: { id } }); } async update(id: number, updateUserDto: any): Promise<User> { await this.userRepository.update(id, updateUserDto); return this.findOne(id); } async remove(id: number): Promise<void> { await this.userRepository.delete(id); } async findByEmail(email: string): Promise<User> { return this.userRepository.findOne({ where: { email } }); } }
Prisma 集成
安装依赖
bashnpm install @prisma/client npm install prisma --save-dev npx prisma init
配置 Prisma
prisma// prisma/schema.prisma datasource db { provider = "mysql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model User { id Int @id @default(autoincrement()) email String @unique password String name String isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }
创建 Prisma 服务
typescriptimport { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common'; import { PrismaClient } from '@prisma/client'; @Injectable() export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy { async onModuleInit() { await this.$connect(); } async onModuleDestroy() { await this.$disconnect(); } }
使用 Prisma
typescriptimport { Injectable } from '@nestjs/common'; import { PrismaService } from './prisma.service'; import { CreateUserDto } from './dto/create-user.dto'; @Injectable() export class UserService { constructor(private prisma: PrismaService) {} async create(createUserDto: CreateUserDto) { return this.prisma.user.create({ data: createUserDto, }); } async findAll() { return this.prisma.user.findMany(); } async findOne(id: number) { return this.prisma.user.findUnique({ where: { id }, }); } async update(id: number, updateUserDto: any) { return this.prisma.user.update({ where: { id }, data: updateUserDto, }); } async remove(id: number) { return this.prisma.user.delete({ where: { id }, }); } }
Mongoose 集成
安装依赖
bashnpm install @nestjs/mongoose mongoose
配置 Mongoose
typescriptimport { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; import { User, UserSchema } from './schemas/user.schema'; import { UserService } from './user.service'; import { UserController } from './user.controller'; @Module({ imports: [ MongooseModule.forRoot('mongodb://localhost:27017/nest'), MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), ], providers: [UserService], controllers: [UserController], }) export class UserModule {}
创建 Schema
typescriptimport { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document } from 'mongoose'; @Schema() export class User extends Document { @Prop({ required: true, unique: true }) email: string; @Prop({ required: true }) password: string; @Prop({ required: true }) name: string; @Prop({ default: true }) isActive: boolean; @Prop({ default: Date.now }) createdAt: Date; @Prop({ default: Date.now }) updatedAt: Date; } export const UserSchema = SchemaFactory.createForClass(User);
创建 Mongoose 服务
typescriptimport { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { User } from './schemas/user.schema'; import { CreateUserDto } from './dto/create-user.dto'; @Injectable() export class UserService { constructor( @InjectModel(User.name) private userModel: Model<User>, ) {} async create(createUserDto: CreateUserDto): Promise<User> { const createdUser = new this.userModel(createUserDto); return createdUser.save(); } async findAll(): Promise<User[]> { return this.userModel.find().exec(); } async findOne(id: string): Promise<User> { return this.userModel.findOne({ _id: id }).exec(); } async update(id: string, updateUserDto: any): Promise<User> { return this.userModel.findByIdAndUpdate(id, updateUserDto, { new: true }).exec(); } async remove(id: string): Promise<User> { return this.userModel.findByIdAndDelete(id).exec(); } }
数据库迁移
TypeORM 迁移
bash# 生成迁移 npm run typeorm migration:generate -- -n CreateUserMigration # 运行迁移 npm run typeorm migration:run # 回滚迁移 npm run typeorm migration:revert
Prisma 迁移
bash# 创建迁移 npx prisma migrate dev --name init # 应用迁移 npx prisma migrate deploy # 重置数据库 npx prisma migrate reset
事务处理
TypeORM 事务
typescriptimport { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, DataSource } from 'typeorm'; import { User } from './entities/user.entity'; import { Order } from './entities/order.entity'; @Injectable() export class OrderService { constructor( private dataSource: DataSource, @InjectRepository(User) private userRepository: Repository<User>, @InjectRepository(Order) private orderRepository: Repository<Order>, ) {} async createOrderWithUser(userId: number, orderData: any) { const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { const user = await queryRunner.manager.findOne(User, { where: { id: userId } }); const order = queryRunner.manager.create(Order, { ...orderData, user, }); await queryRunner.manager.save(order); await queryRunner.commitTransaction(); return order; } catch (err) { await queryRunner.rollbackTransaction(); throw err; } finally { await queryRunner.release(); } } }
Prisma 事务
typescriptasync createOrderWithUser(userId: number, orderData: any) { return this.prisma.$transaction(async (prisma) => { const user = await prisma.user.findUnique({ where: { id: userId }, }); const order = await prisma.order.create({ data: { ...orderData, user: { connect: { id: userId }, }, }, }); return order; }); }
关系映射
TypeORM 关系
typescript@Entity('users') export class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; @OneToMany(() => Order, order => order.user) orders: Order[]; } @Entity('orders') export class Order { @PrimaryGeneratedColumn() id: number; @Column() userId: number; @ManyToOne(() => User, user => user.orders) user: User; @Column() product: string; }
Prisma 关系
prismamodel User { id Int @id @default(autoincrement()) name String orders Order[] } model Order { id Int @id @default(autoincrement()) userId Int user User @relation(fields: [userId], references: [id]) product String }
数据库连接池配置
TypeORM 连接池
typescriptTypeOrmModule.forRoot({ type: 'mysql', host: 'localhost', port: 3306, username: 'root', password: 'password', database: 'test', entities: [__dirname + '/**/*.entity{.ts,.js}'], synchronize: false, extra: { connectionLimit: 10, }, })
Prisma 连接池
prismadatasource db { provider = "mysql" url = env("DATABASE_URL") // 连接池配置 connection_limit = 10 }
最佳实践
- 使用 DTO:使用数据传输对象来验证和转换数据
- 环境变量:使用环境变量管理数据库配置
- 迁移管理:使用迁移来管理数据库结构变更
- 事务处理:在需要原子性操作时使用事务
- 索引优化:为常用查询字段添加索引
- 连接池:合理配置连接池大小
- 软删除:实现软删除而不是物理删除
- 查询优化:避免 N+1 查询问题
总结
NestJS 数据库集成提供了:
- 对多种数据库的支持
- 灵活的 ORM/ODM 选择
- 完整的类型安全
- 强大的关系映射
- 便捷的事务处理
掌握数据库集成是构建数据驱动的 NestJS 应用程序的基础。通过合理选择和使用 ORM/ODM,遵循最佳实践,可以构建出高性能、可维护的数据访问层。