根据环境变量动态连接数据库

一. 连接Mysql数据库

  • 我们之前以及粗略的学习过链接数据库以及环境变量的配置以及校验,那么下面就使用这三者结合起来,实现项目根据环境变量意义开发模式动态的连接对应的数据库

1. app.module.ts(根据环境变量动态链接数据库)

import { Module } from '@nestjs/common';
import { BoysModule } from './boys/boys.module';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config'; // 引入环境配置模块
import * as dotenv from 'dotenv'; // 引入 dotenv 操作环境变量文件
import { ConfigEnum } from './enum/config'; // 引入环境映射关系文件
import * as Joi from 'joi'; // 引入规则校验

// 在 package.json 中配置运行脚本时通过第三方库 cross-env配置当前环境(生产,开发)
const envFilePath = `.env.${process.env.NODE_ENV || `development`}`;

@Module({
imports: [
// forRootAsync方法提供类似于Module的属性,可以引入环境变量的配置模块以及service
TypeOrmModule.forRootAsync({
imports: [ConfigModule], // 引入环境变量配置模块
inject: [ConfigService], // 注入ConfigService
useFactory: (ConfigService: ConfigService) =>
({
/*
数据库类型如果要引用对应环境变量中配置的需要做类型断言,
因为在useFactory中的type属性是有指定类型的
*/
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), // 连接的数据库名(根据环境变量配置)
retryDelay: 500, // 重试连接数据库间隔
retryAttempts: 10, // 允许重连次数

synchronize: ConfigService.get(ConfigEnum.DB_ASYNC), // 设置实体同步到数据库中生成映射关系(根据环境变量配置)
autoLoadEntities: true, // 自动加载实体,,forFeature()注册的每个实体都自己动加载
logging: ['error'], // 日志等级
} as TypeOrmModuleOptions), // 设置类型断言(这里必须设置)
}),
// 连接数据库(单一写法,无法根据环境变量实现灵活对接其他数据库)
// TypeOrmModule.forRoot({
// type: 'mysql', // 数据库类型
// host: 'localhost', // 数据库的连接地址host
// port: 3306, // 数据库的端口 3306
// username: 'root', // 连接账号
// password: '**********', // 连接密码
// database: 'test1', // 连接的数据库名
// retryDelay: 500, // 重试连接数据库间隔
// retryAttempts: 10, // 允许重连次数

// synchronize: true, // 设置实体同步到数据库中生成映射关系
// autoLoadEntities: true, // 自动加载实体,,forFeature()注册的每个实体都自己动加载
// logging: ['error'], // 日志等级
// }),
ConfigModule.forRoot({
isGlobal: true, // 设置为全局环境引入
envFilePath, // 环境参数文件路径
load: [() => dotenv.config({ path: '.env' })], // 使用load来加载公共环境变量(自定义环境变量)

// 设置规则校验(数据库的连接 - 环境变量)
validationSchema: Joi.object({
NODE_ENV: Joi.string()
.valid('development', 'production')
.default('development'), // 可以设置选项中的一项
DB_PORT: Joi.number().default(3306), // 设置数据库端口号必须为数值型且默认值为3306
DB_HOST: Joi.string().ip(), //还可以判断是不是ip类型地址
DB_TYPE: Joi.string().valid('mysql', 'mongodb', 'postgres'), // 限定数据库
DB_DATABASE: Joi.string().required(), // 必须设置
DB_USERNAME: Joi.string().required(), //用户名必须设置
DB_PASSWORD: Joi.string().required(), //密码必须设置
DB_ASYNC: Joi.boolean().default(false),
}),
}),
BoysModule,
],
controllers: [],
providers: [],
})
export class AppModule {}

2. .env.development(环境变量)

# 全局配置环境(一般用于全局配置)
# 局部配置的化推荐在对应的模块文件夹中新建枚举类型

DB = 'Mysql-dev'
DB_HOST = '127.0.0.1' # host
DB_PORT = 3306 # 端口号
DB_USERNAME = 'root' # 用户名
DB_PASSWORD = '**********' # 密码
DB_DATABASE = 'test1' # 库名
DB_TYPE = "mysql" # 数据库类型
DB_ASYNC = true # 映射关系
DB_USER = 'lam' # 公共环境属性

这里就只展示开发环境,不展示生产环境了production(基本一致)

3. enumconfig.ts(环境变量映射关系)

export enum ConfigEnum {
DB = 'DB', // 切记 这里是指向 .env 文件中的 DB
DB_HOST = 'DB_HOST', // 切记 这里是指向 .env 文件中的 DB_HOST
DB_USER = 'DB_USER', // 公共环境变量建立映射
DB_PORT = 'DB_PORT',
DB_USERNAME = 'DB_USERNAME',
DB_PASSWORD = 'DB_PASSWORD',
DB_DATABASE = 'DB_DATABASE',
DB_TYPE = 'DB_TYPE',
DB_ASYNC = 'DB_ASYNC',
}

/*
这样设置的好处是当我们修改 .env 文件中的环境变量时,只需要再次修改
enum中的变量即可(也就是这里),无需改动业务代码
*/

二. 连接MongoDB数据库

  • 连接mongodb数据库就非常的简单了,环境变量以及映射配置与上面的mysql基本一致,官方文档

app.module.ts

import { Module } from '@nestjs/common';
import { UserModule } from './user/user.module';
import { ConfigModule, ConfigService } from '@nestjs/config'; // 引入环境变量配置
import * as dotenv from 'dotenv'; // 引入 dotenv 操作环境变量文件
import * as Joi from 'joi'; // 引入规则校验
import { ConfigEnum } from './enum/config.enum'; // 引入环境映射关系文件
import { MongooseModule, MongooseModuleOptions } from '@nestjs/mongoose';

// 在 package.json 中配置运行脚本时通过第三方库 cross-env配置当前环境(生产,开发)
const envFilePath = `.env.${process.env.NODE_ENV || `development`}`;

@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true, // 设置为全局环境引入
envFilePath, // 环境参数文件路径
load: [() => dotenv.config({ path: '.env' })], // 使用load来加载公共环境变量(自定义环境变量)

// 设置规则校验(数据库的连接 - 环境变量)
validationSchema: Joi.object({
NODE_ENV: Joi.string()
.valid('development', 'production')
.default('development'),
DB_PORT: Joi.number().default(3306),
DB_HOST: Joi.string().ip(),
DB_DATABASE: Joi.string().required(),
DB_USERNAME: Joi.string().required(),
DB_PASSWORD: Joi.string().required(),
}),
}),

// forRootAsync方法提供类似于Module的属性,可以引入环境变量的配置模块以及service
MongooseModule.forRootAsync({
imports: [ConfigModule],// 引入环境变量配置模块
inject: [ConfigService],// 注入ConfigService

/*
数据库类型如果要引用对应环境变量中配置的需要做类型断言,
因为在useFactory中的type属性是有指定类型的
*/
useFactory: (configService: ConfigService) => {
const host = configService.get(ConfigEnum.DB_HOST);
const port = configService.get(ConfigEnum.DB_PORT) || 27017;
const username = configService.get(ConfigEnum.DB_USERNAME);
const password = configService.get(ConfigEnum.DB_PASSWORD);
const database = configService.get(ConfigEnum.DB_DATABASE);

// 拼接数据库连接地址
const uri = username
? `mongodb://${username}:${password}@${host}:${port}/${database}`
: `mongodb://${host}:${port}/${database}`;
return {
uri,// 返回数据库连接地址
retryAttempts: Infinity, // 设置无限重连
retryDelay: 5000, // 重连间隔为5s
} as MongooseModuleOptions; // 设置类型断言(这里必须设置)
},
}),
UserModule,
],
controllers: [],
providers: [],
})
export class AppModule {}