【NestJs】使用连接mysql企业级开发规范

news2024/9/21 18:52:27

本篇将介绍如何建立 NestJs 的数据库连接、并使用数据库联表查询。

简介

Nest 与数据库无关,允许您轻松地与任何 SQL 或 NoSQL 数据库集成。根据您的偏好,您有许多可用的选项。一般来说,将 Nest 连接到数据库只需为数据库加载一个适当的 Node.js 驱动程序,就像使用 Express 或 Fastify 一样。

您还可以直接使用任何通用的 Node.js 数据库集成库或 ORM ,例如 Sequelize (recipe)、knexjs (tutorial)`和 TypeORM ,以在更高的抽象级别上进行操作。

为了方便起见,Nest 还提供了与现成的 TypeORM 与 @nestjs/typeorm 的紧密集成,我们将在本章中对此进行介绍,而与 @nestjs/mongoose 的紧密集成将在这一章中介绍。这些集成提供了附加的特定于 nestjs 的特性,比如模型/存储库注入、可测试性和异步配置,从而使访问您选择的数据库更加容易。

对于一个Web API项目,数据库是必不可少的,Nest与数据库无关,允许您轻松地与任何SQL或NoSQL数据库集成。根据您的偏好,您有许多可用的选项。本篇我们讲解集成MySQL数据库,Nest提供了@nestjs/typeorm包,为了开始使用它,我们首先安装所需的依赖项。

起步

使用 Nest CLI 建立新项目非常简单。 在安装好 npm 后,您可以使用下面命令在您的 OS 终端中创建 Nest 项目:

$ npm i -g @nestjs/cli
$ nest new project-name

要创建启用 TypeScript strict模式的新项目,请将 --strict 标志传递给 nest new 命令

将会创建 project-name 目录, 安装 node_modules 和一些其他样板文件,并将创建一个 src 目录,目录中包含几个核心文件。

src
 ├── app.controller.spec.ts
 ├── app.controller.ts
 ├── app.module.ts
 ├── app.service.ts
 └── main.ts

以下是这些核心文件的简要概述:

app.controller.ts带有单个路由的基本控制器示例。
app.controller.spec.ts对于基本控制器的单元测试样例
app.module.ts应用程序的根模块。
app.service.ts带有单个方法的基本服务
main.ts应用程序入口文件。它使用 NestFactory 用来创建 Nest 应用实例。
main.ts包含一个异步函数,它负责引导我们的应用程序:

连接mysql

为了与 SQL和 NoSQL 数据库集成,Nest 提供了 @nestjs/typeorm 包。Nest 使用TypeORM是因为它是 TypeScript 中最成熟的对象关系映射器( ORM )。因为它是用 TypeScript 编写的,所以可以很好地与 Nest 框架集成。

为了开始使用它,我们首先安装所需的依赖项。在本章中,我们将演示如何使用流行的关系型数据库 Mysql , TypeORM 提供了对许多关系数据库的支持,比如 PostgreSQL 、Oracle、Microsoft SQL Server、SQLite,甚至像 MongoDB 这样的 NoSQL 数据库。我们在本章中介绍的步骤对于 TypeORM 支持的任何数据库都是相同的。您只需为所选数据库安装相关的客户端 API 库。

npm install --save @nestjs/typeorm typeorm mysql2

安装过程完成后,我们可以将 TypeOrmModule 导入AppModule 。

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'root',
      database: 'test',
      entities: [],
      synchronize: true,
    }),
  ],
})
export class AppModule {}

警告:设置 synchronize: true 不能被用于生产环境,否则您可能会丢失生产环境数据

mysql2用于node.js来操作mysql的库;
typeorm一个orm库,可以理解为把对象和表做了一个映射关系,来方便操作;
@nestjs/typeormnestjs基于typeorm的封装。

犹豫前面我们已经介绍了dotenv 配置文件,那么我们就可以使用配置文件的方式使用

存储库模式

TypeORM 支持存储库设计模式,因此每个实体都有自己的存储库。可以从数据库连接获得这些存储库。
创建user.entity.ts

import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

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

  @Column()
  firstName: string;

  @Column()
  lastName: string;

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

User 实体在 users 目录下。这个目录包含了和 UsersModule模块有关的所有文件。你可以决定在哪里保存模型文件,但我们推荐在他们的域中就近创建,即在相应的模块目录中。

要开始使用user实体,我们需要在模块的forRoot()方法的选项中(除非你使用一个静态的全局路径)将它插入entities数组中来让 TypeORM知道它的存在。

为了继续这个示例,我们需要至少一个实体。我们来定义User 实体。

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: 'root',
      database: 'test',
      entities: [User],
      synchronize: true,
    }),
  ],
})
export class AppModule {}

现在让我们看一下 UsersModule:

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

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

此模块使用 forFeature() 方法定义在当前范围中注册哪些存储库。这样,我们就可以使用 @InjectRepository()装饰器将 UsersRepository 注入到 UsersService 中:
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: string): Promise<User> {
    return this.usersRepository.findOne(id);
  }

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

不要忘记将 UsersModule 导入根 AppModule。

如果是简单的项目可以这样 粗暴一点,直接写的 app.module.ts里面,那要是企业级的开发肯定不允许这样做的,首先 该模块会非常的臃肿,而且不符合开发规范,那么我们需要使用配置文件导入到app.module.ts 里面,这样 如果修改数据库相关的配置,只需要修改配置文件即可。

使用配置文件之前我们还是需要了解以下几个库:

dotenv 模块

首先先介绍一下在行业里面应用非常广泛的dotenv,,由于项目不同需求,需要配置不同环境变量,按需加载不同的环境变量文件,使用dotenv,可以完美解决这一问题。
在这里插入图片描述
使用

npm install dotenv --save

Usage Create a .env file in the root of your project:

S3_BUCKET="YOURS3BUCKET"
SECRET_KEY="YOURSECRETKEYGOESHERE"
As early as possible in your application, import and configure dotenv:

require('dotenv').config()
console.log(process.env) // remove this after you've confirmed it is working

如需了解更多则可以去查看https://www.npmjs.com/package/dotenv

配置项目

1. 配置文件

创建 .env 文件 主要用于配置变量 内置dotenv

  1. 创建dotenv 文件
    在项目第一级文件夹创建 一个 .env 文件
DB_TYPE=mysql
DB_HOST=127.0.0.1
DB_PORT=3306

DB_SYNC=false

开发环境env

DB_DATABASE=testdb
DB_HOST=127.0.0.1
DB_PORT=3306

DB_USERNAME=root
DB_PASSWORD=123456

# 用在开发过程中,作用:同步实体->数据库
DB_SYNC=true

生产环境中的env

DB_DATABASE=proddb
DB_HOST=xxx.xxx
DB_PORT=3306

DB_USERNAME=root
DB_PASSWORD=long-password

DB_SYNC=true

这样做的好处就是 以后方便使用和切换各个环境

2. 安装 @nestjs/config

@nestjs/config依赖于dotenv,可以通过key=value形式配置环境变量,项目会默认加载根目录下的.env文件,我们只需在app.module.ts中引入ConfigModule,再使用ConfigModule.forRoot()方法即可。

npm i --save @nestjs/config

app.modules.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
import * as dotenv from 'dotenv';
import * as Joi from 'joi';
const envFilePath = `.env.${process.env.NODE_ENV || `development`}`;

@Module({
  // ConfigModule.forRoot() 可以使用env 文件中的常量
  imports: [
      ConfigModule.forRoot({
      // 全局可以使用
      isGlobal: true,
      envFilePath,
      load: [() => dotenv.config({ path: '.env' })],
    }),
    TypeOrmModule.forRootAsync({
      useFactory: () => ({
        type: 'mysql',
        host: process.env.DB_HOST,
        port: process.env.DB_PORT,
        username: process.env.DB_USERNAME,
        password: process.env.DB_PASSWORD,
        database: process.env.DB_DATABASE,
        timezone: 'UTC',
        charset: 'utf8mb4',
        entities: ['./**/*.entity.js'],
        synchronize: true,
        logging: true,
    })})],
	],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

上述代码将从默认位置(项目根目录)载入并解析一个.env文件,从.env文件和process.env合并环境变量键值对,并将结果存储到一个可以通过ConfigService访问的私有结构。forRoot()方法注册了ConfigService提供者,后者提供了一个get()方法来读取这些解析/合并的配置变量。

3. 配置校验Joi

Joi是一个广泛使用的Node.js数据验证库,提供了一个简单、直观、可读的API来描述数据。它主要用于验证从API端点发送的数据,并允许你创建你想接受的数据类型的蓝图。

下面是一个用Joi描述模式的简单例子:

 const schema = Joi.object().keys({ 
     name: Joi.string().alphanum().min(3).max(30).required(),
     birthyear: Joi.number().integer().min(1970).max(2013), 
});

配置验证,主要是指在应用程序启动时,如果没有提供所需的环境变量或不符合某些验证规则,就会抛出一个异常。@nestjs/config包实现了两种不同的方式来实现这一点。

  • Joi内置验证器。通过]gi,你可以定义一个对象模式,并根据它验证JavaScript对象
  • 一个自定义的validate()函数,它将环境变量作为输入
    特别说明:
    最新版本的joi 需要你运行Node v12或更高版本。旧版本的node请安装v16.1.8。这主要是因为在v17.0.2发布后,在构建的时候会出现错误。更多信息请参考其17.0.0发布说明.
    安装依赖
npm install --save joi

使用

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
import * as dotenv from 'dotenv';
import * as Joi from 'joi';
const envFilePath = `.env.${process.env.NODE_ENV || `development`}`;
@Module({
  // ConfigModule.forRoot() 可以使用env 文件中的常量
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath,
      load: [() => dotenv.config({ path: '.env' })],
      validationSchema: Joi.object({
        NODE_ENV: Joi.string()
          .valid('development', 'production')
          .default('development'),
        DB_PORT: Joi.number().default(3306),
        DB_HOST: Joi.string().ip(),
        DB_TYPE: Joi.string().valid('mysql', 'postgres'),
        DB_DATABASE: Joi.string().required(),
        DB_USERNAME: Joi.string().required(),
        DB_PASSWORD: Joi.string().required(),
        DB_SYNC: Joi.boolean().default(false),
      }),
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

4. 加载自定义配置文件

上面我们把数据库的信息都写在了环境变量中,再通过process.env.key形式去获取,但可能存在下面一种需求:config文件夹下存在config.enum.ts 配置文件,需根据NODE_ENV加载不同配置文件;此外需要一种扩展性更好的配置文件格式支持,比如.ts,.js文件,这时可以将数据库配置项等作为一个对象,而不仅仅是key=value的格式,同时也能附加注释、说明等内容。下面我们在config文件夹中增加配置文件,app.module.ts文件再作修改,数据库信息等移至配置文件中。

export enum ConfigEnum {
  DB_TYPE = 'DB_TYPE',
  DB_HOST = 'DB_HOST',
  DB_PORT = 'DB_PORT',
  DB_DATABASE = 'DB_DATABASE',
  DB_USERNAME = 'DB_USERNAME',
  DB_PASSWORD = 'DB_PASSWORD',
  DB_SYNC = 'DB_SYNC',
}

import { Module } from '@nestjs/common';
import { UserModule } from './user/user.module';
import { ConfigModule, ConfigService } from '@nestjs/config';
import * as dotenv from 'dotenv';
import * as Joi from 'joi';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { ConfigEnum } from './enum/config.enum';

const envFilePath = `.env.${process.env.NODE_ENV || `development`}`;

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath,
      load: [() => dotenv.config({ path: '.env' })],
      validationSchema: Joi.object({
        NODE_ENV: Joi.string()
          .valid('development', 'production')
          .default('development'),
        DB_PORT: Joi.number().default(3306),
        DB_HOST: Joi.string().ip(),
        DB_TYPE: Joi.string().valid('mysql', 'postgres'),
        DB_DATABASE: Joi.string().required(),
        DB_USERNAME: Joi.string().required(),
        DB_PASSWORD: Joi.string().required(),
        DB_SYNC: Joi.boolean().default(false),
      }),
    }),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (configService: ConfigService) =>
        ({
          type: configService.get(ConfigEnum.DB_TYPE),
          host: configService.get(ConfigEnum.DB_HOST),
          port: configService.get(ConfigEnum.DB_PORT),
          username: configService.get(ConfigEnum.DB_USERNAME),
          password: configService.get(ConfigEnum.DB_PASSWORD),
          database: configService.get(ConfigEnum.DB_DATABASE),
          entities: [],
          // 同步本地的schema与数据库 -> 初始化的时候去使用
          synchronize: configService.get(ConfigEnum.DB_SYNC),
          logging: process.env.NODE_ENV === 'development',
          // logging: ['error'],
        } as TypeOrmModuleOptions),
    }),
    // TypeOrmModule.forRoot({
    //   type: 'mysql',
    //   host: 'localhost',
    //   port: 3306,
    //   username: 'root',
    //   password: 'example',
    //   database: 'testdb',
    //   entities: [],
    //   // 同步本地的schema与数据库 -> 初始化的时候去使用
    //   synchronize: true,
    //   logging: ['error'],
    // }),
    UserModule,
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

运行项目,用数据库管理工具连接我们的数据库,可以发现,我们就完成了数据库的连接。

接下来将讲解 怎么创建实体连接完数据库之后创建实体

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/440735.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Delphi DataSnap 流程分析(一)

DataSnap 有三种方式: 1、DataSnap REST Application: Create a DataSnap Server with support for REST Communication and with pages that invoke server methods using Java Script and JSON. 2、DataSnap Server: The DataSnap Server Wizard provides an easy way to i…

怎么把视频中动态的人物P掉,把视频中不要的人物去掉

怎么把视频中动态的人物P掉&#xff1f;很多小伙伴试过ps抠图&#xff0c;但是你试过视频人物抠图吗&#xff1f;其实道理是一样的&#xff0c;但是操作过程却变难了。今天就给大家带来一个简单的方法&#xff0c;轻松去除视频中的人物。不影响整个画面的呈现。 在拍摄旅游视频…

springcloud:快速上手定时任务框架xxl-job(十五)

0. 引言 实际开发中&#xff0c;我们常常遇到需要定时执行的任务&#xff0c;我们可以利用定时线程池或schedule框架等来实现定时任务&#xff0c;但这些方式都有效率、性能上的缺陷&#xff0c;在微服务框架下&#xff0c;我们期望一种更加规整、轻量、可靠的定时任务框架来帮…

【通信接口】UART、IIC、SPI

目录 一、预备知识 1、串行与并行 2、单工与双工 3、波特率 二、UART 三、IIC 四、SPI &#xff08;一对一、一对多&#xff09; 五、IIC、SPI异同点 参考文章&#xff1a;这些单片机接口&#xff0c;一定要熟悉&#xff1a;UART、I2C、SPI、TTL、RS232、RS422、RS485…

kafka-5 kafka的高吞吐量和高可用性

kafka的高吞吐量和高可用性 6.1 高吞吐量6.2 高可用&#xff08;HA&#xff09; 6.1 高吞吐量 kafka的高吞吐量主要是由4方面保证的&#xff1a; &#xff08;1&#xff09;顺序读写磁盘 Kafka是将消息持久化到本地磁盘中的&#xff0c;一般人会认为磁盘读写性能差&#xff…

【C++ 八】写文件、读文件

写文件、读文件 文章目录 写文件、读文件前言1 文本文件1.1 写文件1.2 读文件 2 二进制文件2.1 写文件2.2 读文件 前言 本文包含文本文件写文件、文本文件读文件、二进制写文件、二进制读文件。 程序运行时产生的数据都属于临时数据&#xff0c;程序一旦运行结束都会被释放 通…

中间表示- 活性分析

进行活性分析的动机 &#xff08;1&#xff09;在代码生成的讨论中&#xff0c;我们曾假设目标机器有无限多个&#xff08;虚拟&#xff09;寄存器可用&#xff0c;这简化了代码生成的算法&#xff0c;但对物理机器是个坏消息&#xff0c;因为机器只有有限多个寄存器&#xff…

Spring Boot 应用的打包和发布

1. 创建项目&#xff08;example-fast&#xff09; 基于 Spring Boot 创建一个 WEB 项目 example-fast。 2. 编译打包 2.1 采用 IDEA 集成的 Maven 环境来对 Spring Boot 项目编译打包&#xff0c;可谓是超级 easy 2.2 mvn 命令打包 # mvn clean 清理编译 # install 打包 #…

牛顿法、梯度下降法与拟牛顿法

牛顿法、梯度下降法与拟牛顿法 0 引言1 关于泰勒展开式1.1 原理1.2 例子 2 牛顿法2.1 x 为一维2.2 x 为多维 3 梯度下降法4 拟牛顿法4.1 拟牛顿条件4.2 DFP 算法4.3 BFGS 算法4.4 L-BFGS 算法 0 引言 机器学习中在求解非线性优化问题时&#xff0c;常用的是梯度下降法和拟牛顿…

数据结构入门(C语言版)二叉树概念及结构(入门)

二叉树概念及结构&#xff08;入门&#xff09; 树的概念及结构1.树的概念及结构1.1 树的概念1.2 树的相关知识1.3 树的结构体表示1.4 树的实际运用 2.二叉树概念及结构2.1 二叉树的概念2.2 现实中的二叉树2.3 特殊的二叉树2.4 二叉树的性质2.5 二叉树的存储结构 结语 树的概念…

【SpringCloud】3、使用Nacos作为服务配置中心

1、增加 maven 依赖 <!-- SpringCloud Alibaba Nacos Config --> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>2、添加配置中心配置 spr…

(数字图像处理MATLAB+Python)第四章图像正交变换-第四、五节:Radon变换和小波变换

文章目录 一&#xff1a;Radon变换&#xff08;1&#xff09;Radon变换原理&#xff08;2&#xff09;Radon变换实现&#xff08;3&#xff09;Radon变换性质&#xff08;4&#xff09;Radon变换应用 二&#xff1a;小波变换&#xff08;1&#xff09;小波A&#xff1a;定义B&a…

【PyQt】PyQt5进阶——串口上位机及实时数据显示

文章目录 0 前期教程1 前言2 串口部分——QtSerialPort3 绘图部分3.1 QCustomPlot3.2 QtChart3.3 QWT3.4 Qt Designer中如何使用 参考链接 0 前期教程 【Python】PyQt5入门 1 前言 最近在用PyQt做一个串口上位机&#xff0c;需要串口通信和实时显示曲线。这里简单记录一些关键…

【已解决】最简单便捷的方法将多html合并为pdf

一、单页面转pdf 可以使用pdf24&#xff0c;https://tools.pdf24.org/zh/webpage-to-pdf。 也可以直接打印 二、多页面转pdf&#xff08;wkhtmltopdf方案&#xff09; 1、安装配置pdfkit&#xff1a;[https://blog.csdn.net/xc_zhou/article/details/80952168(https://blog.…

Charles安装及使用教程

一. 简介及安装 一、charles的使用 1.1 charles的说明 Charles其实是一款代理服务器&#xff0c;通过过将自己设置成系统&#xff08;电脑或者浏览器&#xff09;的网络访问代理服务器&#xff0c;然后截取请求和请求结果达到分析抓包的目的。该软件是用Java写的&#xff0…

Nestjs全网最佳翻译-概况-管道-Pipes

管道 带上装饰器 Injectable() 并实现了 PipeTransform 接口的类&#xff0c;就是管道。 管道有 2 个典型的应用场景&#xff1a; 数值转换&#xff1a;将输入的参数转换成目标类型&#xff0c;例如&#xff0c;string to number。 数值校验&#xff1a;对输入的参数进行校验…

cocos creator v3.6版本使用Intersection2D模块的circleCircle方法

在cocos creator v3版本中Intersection2D模块的circleCircle方法可以用来检测两个圆形是否相交 该方法可以实现的功能有&#xff1a; cocos creator吸铁石实现、cocos creator物体在固定位置吸附、cocos creator物体吸附效果、cocos creator吸铁石实现、cocos creator两个物体时…

统计软件与数据分析Lesson9----爬虫解析库Beautiful Soup

统计软件与数据分析Lesson9----爬虫解析库Beautiful Soup知识点总结 1.requests 模块1.1 查看requests功能函数1.2 发送请求1.3 传递URL参数1.4 获取响应内容 2.Beautiful Soup模块2.1 解析器2.2 对象类型2.2.1 Beautiful Soup2.2.2 标签Tag2.2.3 可遍历的字符串NavigableStrin…

Java——包含min函数的栈

题目链接 牛客在线oj题——包含min函数的栈 题目描述 定义栈的数据结构&#xff0c;请在该类型中实现一个能够得到栈中所含最小元素的 min 函数&#xff0c;输入操作时保证 pop、top 和 min 函数操作时&#xff0c;栈中一定有元素。 此栈包含的方法有&#xff1a; push(va…

SRv6实践项目(六):控制面完成链路和主机的发现

在本次实验中&#xff0c;我们需要利用ONOS完成对数据面的控制 1.使能packet的IO功能&#xff0c;验证链路发现 main.p4提供了和P4Runtime的通信的消息的定义格式&#xff0c;分别是PacketIn和PacketOut&#xff0c;他们都被加上了一个注解&#xff0c;表示这是一个控制器交互…