在本章中,我们将学习如何在 NestJS 应用程序中集成数据库。数据库是大多数应用程序必不可少的一部分,它用于存储和管理数据。NestJS 支持多种数据库的集成,包括关系型数据库和非关系型数据库。
# 4.1 安装数据库驱动
在集成数据库之前,我们需要先安装相应的数据库驱动。NestJS 支持许多数据库驱动,例如:
- TypeORM:适用于关系型数据库的对象关系映射(ORM)库,支持 MySQL、-PostgreSQL、SQLite、MariaDB、SQL Server 等数据库。
- Mongoose:适用于 MongoDB 的对象模型库。 这里我们以 TypeORM 为例来进行数据库集成。
首先,我们需要安装 TypeORM 和相关依赖:
npm install @nestjs/typeorm typeorm mysql
- @nestjs/typeorm:NestJS 提供的 TypeORM 模块。
- typeorm:TypeORM 库。
- mysql:MySQL 数据库驱动(根据实际数据库选择对应的驱动)。
# 4.2 创建数据库连接
在使用 TypeORM 之前,我们需要先创建数据库连接。在 NestJS 中,我们使用 TypeOrmModule.forRoot() 方法来创建数据库连接。
打开 app.module.ts 文件,并添加以下代码:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql', // 数据库类型
host: 'localhost', // 数据库主机地址
port: 3306, // 数据库端口号
username: 'your_username', // 数据库用户名
password: 'your_password', // 数据库密码
database: 'your_database', // 数据库名
autoLoadEntities: true, // 自动加载实体
synchronize: true, // 自动同步数据库结构,谨慎使用生产环境
}),
],
})
export class AppModule {}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在上面的代码中,我们通过 TypeOrmModule.forRoot() 方法来创建一个 MySQL 数据库连接。你需要根据实际情况,修改 type、host、port、username、password 和 database 等参数来配置数据库连接。
注意:在生产环境中,不建议使用 synchronize: true,因为它会自动创建数据库表结构和索引,可能会导致数据丢失。在生产环境中,应该手动管理数据库结构。
# 4.3 创建实体
在 TypeORM 中,实体是映射到数据库表的 JavaScript 类。每个实体类代表数据库表中的一行数据。
我们先创建一个 Cat 实体,用于映射到数据库中的 cats 表。在 cats 表中,我们将包含 id、name 和 age 字段。
首先,在 src 目录下创建一个新的文件 cat.entity.ts,并添加以下代码:
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Cat {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
age: number;
}
2
3
4
5
6
7
8
9
10
11
12
13
在上面的代码中,我们使用 @Entity() 装饰器来定义一个实体类 Cat。@PrimaryGeneratedColumn() 装饰器定义了主键字段 id,@Column() 装饰器定义了普通字段 name 和 age。
# 4.4 创建数据库仓库
在 TypeORM 中,数据库仓库用于对数据库表进行 CRUD(增删改查)操作。每个实体类都需要一个对应的数据库仓库。
我们创建一个 CatsRepository 数据库仓库来对 Cat 实体进行操作。
首先,在 src 目录下创建一个新的文件 cats.repository.ts,并添加以下代码:
import { EntityRepository, Repository } from 'typeorm';
import { Cat } from './cat.entity';
@EntityRepository(Cat)
export class CatsRepository extends Repository<Cat> {}
2
3
4
5
在上面的代码中,我们使用 @EntityRepository() 装饰器来定义一个数据库仓库类 CatsRepository,并传入 Cat 实体作为泛型参数。
# 4.5 使用数据库仓库
现在我们已经创建了数据库连接、实体和数据库仓库,可以在服务中使用数据库仓库来进行数据库操作了。
首先,我们在 cats.service.ts 中引入 CatsRepository:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { CatsRepository } from './cats.repository';
import { Cat } from './cat.entity';
@Injectable()
export class CatsService {
constructor(
@InjectRepository(CatsRepository)
private catsRepository: CatsRepository,
) {}
// 在这里可以使用 this.catsRepository 对数据库进行增删改查操作
}
2
3
4
5
6
7
8
9
10
11
12
13
14
在上面的代码中,我们使用 @InjectRepository() 装饰器来注入 CatsRepository 作为 catsRepository 成员变量。
现在,CatsService 中就可以使用 this.catsRepository 对数据库进行增删改查操作了。
# 4.6 使用服务进行数据库操作
在上一节中,我们已经创建了 CatsService 服务,并注入了 CatsRepository。现在,我们可以在 CatsService 中使用 CatsRepository 来对数据库进行操作。
在 cats.service.ts 文件中,我们可以添加一些方法来实现对 Cat 实体的增删改查操作。
在 CatsService 中添加对 Cat 实体的增删改查操作:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { CatsRepository } from './cats.repository';
import { Cat } from './cat.entity';
@Injectable()
export class CatsService {
constructor(
@InjectRepository(CatsRepository)
private catsRepository: CatsRepository,
) {}
async findAll(): Promise<Cat[]> {
return this.catsRepository.find();
}
async findById(id: number): Promise<Cat> {
return this.catsRepository.findOne(id);
}
async create(cat: Cat): Promise<Cat> {
return this.catsRepository.save(cat);
}
async update(id: number, updates: Partial<Cat>): Promise<Cat> {
const cat = await this.findById(id);
if (!cat) {
throw new Error('Cat not found');
}
Object.assign(cat, updates);
return this.catsRepository.save(cat);
}
async delete(id: number): Promise<void> {
await this.catsRepository.delete(id);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
在上面的代码中,我们添加了 findAll 方法来查询所有的猫,findById 方法来根据猫的 ID 查询单个猫,create 方法来创建新的猫,update 方法来更新猫的信息,delete 方法来删除猫。
在这些方法中,我们直接使用了 catsRepository 对数据库进行操作。例如,
- this.catsRepository.find() 查询所有的猫,
- this.catsRepository.findOne(id) 根据猫的 ID 查询单个猫,
- this.catsRepository.save(cat) 创建新的猫或更新猫的信息,
- this.catsRepository.delete(id) 删除猫。
# 4.7 使用控制器调用服务方法
现在我们已经创建了数据库连接、实体、数据库仓库和服务,接下来我们需要使用控制器来调用服务方法。
在 cats.controller.ts 文件中,我们引入 CatsService 并添加以下代码:
import { Controller, Get, Post, Put, Delete, Body, Param } from '@nestjs/common';
import { CatsService } from './cats.service';
import { Cat } from './cat.entity';
@Controller('cats')
export class CatsController {
constructor(private catsService: CatsService) {}
@Get()
async findAll(): Promise<Cat[]> {
return this.catsService.findAll();
}
@Get(':id')
async findById(@Param('id') id: number): Promise<Cat> {
return this.catsService.findById(id);
}
@Post()
async create(@Body() cat: Cat): Promise<Cat> {
return this.catsService.create(cat);
}
@Put(':id')
async update(@Param('id') id: number, @Body() updates: Partial<Cat>): Promise<Cat> {
return this.catsService.update(id, updates);
}
@Delete(':id')
async delete(@Param('id') id: number): Promise<void> {
return this.catsService.delete(id);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
在上面的代码中,我们通过构造函数注入了 CatsService,并在控制器中使用 CatsService 的方法来实现对猫的增删改查操作。
这样,我们就完成了数据库集成的步骤。现在,当我们发送 GET、POST、PUT 和 DELETE 请求到 /cats 路径时,NestJS 会自动调用相应的控制器方法,并通过服务调用数据库仓库进行数据库操作。
# 4.8 额外的数据库操作
除了基本的增删改查操作,TypeORM 还提供了许多其他数据库操作功能,如使用查询构建器、使用原生 SQL 查询、使用事务等。在实际应用中,我们可以根据需求来选择使用这些功能。
例如,我们可以使用查询构建器来执行复杂的查询:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { CatsRepository } from './cats.repository';
import { Cat } from './cat.entity';
@Injectable()
export class CatsService {
constructor(
@InjectRepository(CatsRepository)
private catsRepository: CatsRepository,
) {}
async findByName(name: string): Promise<Cat[]> {
return this.catsRepository
.createQueryBuilder('cat')
.where('cat.name = :name', { name })
.getMany();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
在上面的代码中,我们使用查询构建器来执行一个名为 findByName 的查询,该查询会查找所有名字为给定参数 name 的猫。
TypeORM 还提供了许多其他高级特性,如数据迁移、数据库关系、联表查询等。在实际应用中,我们可以根据需求和项目的复杂程度来选择适合的数据库操作方式。