> 文章列表 > 【NestJs】数据库重构

【NestJs】数据库重构

【NestJs】数据库重构

上一篇文章详细了介绍nestjs 配置数据库,有不懂的小伙伴可以先查看上一篇文章【NestJs】使用连接mysql企业级开发规范在继续往下。
今天这一篇文章主要是针对配置数据库的重构,使用代码规范,方便后期维护。
当应用变得复杂 我们需要借用TypeORM CLI 非常方便的调整。

注意:
TypeORM 读取到extensions 结尾的文件
【NestJs】数据库重构
但是在根目录的文件 不能进行动态的修改,这样的话变量一旦很多的,修改极其麻烦。
【NestJs】数据库重构
当然 我们选择 ormconfig.ts ,不过因为我们环境不止一个。需要多多个环境校验。

使用 CLI

此 CLI 工具使用 javascript 编写,并在 node 上运行。如果你的实体文件是 TypeScript 编写,则需要在使用 CLI 之前将它们转换为 javascript。如果只使用 javascript,则可以跳过此部分。

全局安装 ts-node:

你可以在项目中设置 ts-node 以简化操作,如下所示:

npm install ts-node --save-dev

在 package.json 中的 scripts 下添加 typeorm 命令

"script" {..."typeorm": "typeorm-ts-node-commonjs"
}

注意:
typeorm 该版本使用的是 “typeorm”: “0.3.7” 要是版本不一致 需要查看官方文档最新使用方法。

根目录创建文件ormconfig.ts,我们需要把app.module.ts配置的数据库迁移:

import { User } from './src/user/user.entity';
import { Profile } from './src/user/profile.entity';
import { Logs } from './src/logs/logs.entity';
import { Roles } from './src/roles/roles.entity';
import { TypeOrmModuleOptions } from '@nestjs/typeorm';export default {type: 'mysql',host: 'localhost',port: 3306,username: 'root',password: '123456',database: 'testdb',entities: [User, Profile, Logs, Roles],// 同步本地的schema与数据库 -> 初始化的时候去使用synchronize: true,// logging: process.env.NODE_ENV === 'development',logging: false,
} as TypeOrmModuleOptions;

app.module.ts

import { Global, Logger, Module } from '@nestjs/common';
import { UserModule } from './user/user.module';
import { ConfigModule } from '@nestjs/config';
import * as dotenv from 'dotenv';
import * as Joi from 'joi';
import { TypeOrmModule } from '@nestjs/typeorm';import { LogsModule } from './logs/logs.module';
import { RolesModule } from './roles/roles.module';
import ormconfig from '../ormconfig';const envFilePath = `.env.${process.env.NODE_ENV || `development`}`;@Global()
@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.forRoot(ormconfig),UserModule,LogsModule,RolesModule,],controllers: [],providers: [Logger],exports: [Logger],
})
export class AppModule {}

【NestJs】数据库重构
到这里 说明连接成功了。

初始化一个新的TypeORM项目

它使用 TypeORM 创建基本项目所需的所有文件:

  • .gitignore
  • package.json
  • README.md
  • tsconfig.json
  • ormconfig.json
  • src/entity/User.ts
  • src/index.ts
    然后你可以运行npm install来安装所有依赖项。 一旦安装了所有依赖项,你需要修改ormconfig.json并插入您自己的数据库设置。 之后,可以通过运行npm start来运行您的应用程序。

要指定使用的特定数据库,可以使用–database:

npx typeorm init --database mysql2

生成文件data-source.ts 文件结构和ormconfig 类似,

import 'reflect-metadata';
import { DataSource } from 'typeorm';
import { User } from './entity/User';export const AppDataSource = new DataSource({synchronize: true,logging: false,entities: [User],migrations: [],subscribers: [],
});

也会生成一个entity文件夹,暂时不用 我们可以先删掉,根据文档我们需要使用new DataSource 接下来需要修改 ormconnfig.ts 文件

import { User } from './src/user/user.entity';
import { Profile } from './src/user/profile.entity';
import { Logs } from './src/logs/logs.entity';
import { Roles } from './src/roles/roles.entity';
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { DataSource, DataSourceOptions } from 'typeorm';export const connectionParams = {type: 'mysql',host: 'localhost',port: 3306,username: 'root',password: '123456',database: 'testdb',entities: [User, Profile, Logs, Roles],// 同步本地的schema与数据库 -> 初始化的时候去使用synchronize: true,// logging: process.env.NODE_ENV === 'development',logging: false,
} as TypeOrmModuleOptions;export default new DataSource({...connectionParams,migrations: ['src/migrations/'],
} as DataSourceOptions);

测试:
修改index.ts

import AppDataSource from '../ormconfig';
import { User } from './user/user.entity';AppDataSource.initialize().then(async () => {const res = await AppDataSource.manager.find(User);console.log(res);}).catch((error) => console.log(error));
npx ts-node src/index.ts

结果:
【NestJs】数据库重构
到此 我们已经完成了一半。

我们需要使用ormconfig 对接不同的环境?
通过环境变量读取不用的.env文件, 通过dotENV来解析不同的配置:

import { TypeOrmModuleOptions } from '@nestjs/typeorm';import { DataSource, DataSourceOptions } from 'typeorm';
import * as fs from 'fs';
import * as dotenv from 'dotenv';
import { ConfigEnum } from './src/enum/config.enum';// 通过环境变量读取不同的.env文件
function getEnv(env: string): Record<string, unknown> {if (fs.existsSync(env)) {return dotenv.parse(fs.readFileSync(env));}return {};
}// 通过dotENV来解析不同的配置
function buildConnectionOptions() {const defaultConfig = getEnv('.env');const envConfig = getEnv(`.env.${process.env.NODE_ENV || 'development'}`);// configServiceconst config = { ...defaultConfig, ...envConfig };// 过多的实体 我们就不需要一个一个的导入加载const entitiesDir =process.env.NODE_ENV === 'test'? [__dirname + '//*.entity.ts']: [__dirname + '//*.entity{.js,.ts}'];return {type: config[ConfigEnum.DB_TYPE],host: config[ConfigEnum.DB_HOST],port: config[ConfigEnum.DB_PORT],username: config[ConfigEnum.DB_USERNAME],password: config[ConfigEnum.DB_PASSWORD],database: config[ConfigEnum.DB_DATABASE],entities: entitiesDir,// 同步本地的schema与数据库 -> 初始化的时候去使用synchronize: true,// logging: process.env.NODE_ENV === 'development',logging: false,} as TypeOrmModuleOptions;
}export const connectionParams = buildConnectionOptions();export default new DataSource({...connectionParams,migrations: ['src/migrations/'],subscribers: [],
} as DataSourceOptions);

app.module.ts Joi 的配置需要修改一下:

import { Global, Logger, Module } from '@nestjs/common';
import { UserModule } from './user/user.module';
import { ConfigModule } from '@nestjs/config';
import * as dotenv from 'dotenv';
import * as Joi from 'joi';
import { TypeOrmModule } from '@nestjs/typeorm';import { LogsModule } from './logs/logs.module';
import { RolesModule } from './roles/roles.module';import { connectionParams } from '../ormconfig';const envFilePath = `.env.${process.env.NODE_ENV || `development`}`;@Global()
@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),// 生产环境和部署环境可能 HOST 一个是ip 一个是网址一样DB_HOST: Joi.alternatives().try(Joi.string().ip(),Joi.string().domain(),),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),LOG_ON: Joi.boolean(),LOG_LEVEL: Joi.string(),}),}),TypeOrmModule.forRoot(connectionParams),UserModule,LogsModule,RolesModule,],controllers: [],providers: [Logger],exports: [Logger],
})
export class AppModule {}

最后就是package.json 中 按照官方文档修改的配置:

"scripts": {"prebuild": "rimraf dist","build": "cross-env NODE_ENV=production nest build","format": "prettier --write \\"src//*.ts\\" \\"test//*.ts\\"","start": "ts-node src/index.ts","start:dev": "cross-env NODE_ENV=development nest start --watch","start:debug": "cross-env NODE_ENV=development nest start --debug --watch","start:prod": "cross-env NODE_ENV=production node dist/src/main","lint": "eslint \\"{src,apps,libs,test}//*.ts\\" --fix","test": "jest","test:watch": "jest --watch","test:cov": "jest --coverage","test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand","test:e2e": "jest --config ./test/jest-e2e.json","typeorm": "typeorm-ts-node-commonjs -d ormconfig.ts","migration:generate": "f() { npm run typeorm migration:generate -p \\"./src/migrations/$@\\"; }; f","migration:create": "typeorm-ts-node-commonjs migration:create","migration:run": "npm run typeorm migration:run","migration:revert": "npm run typeorm migration:revert","schema:drop": "npm run typeorm schema:drop"},

运行代码即可。