天天看點

nest 內建mysql typeorm 并實作資料遷移

前提假設本地的mysql環境安裝完成

1、 安裝typeorm和mysql

$ npm install --save @nestjs/typeorm typeorm mysql2 nestjs-config
           

2、導入到AppModule中

采用的是cofing的模式導入配置資訊

異步配置參考位址

在src目錄下建立config檔案

database.config.ts

export default {
  type: process.env.DB_TYPE,
  host: process.env.DB_HOST,
  port: Number(process.env.DB_PORT),
  database: process.env.DB_DATABASE,
  username: process.env.DB_USERNAME,
  password: process.env.DB_PASSWORD,
  logging: true,
};

           

.env

PREFIX=api/v1
PORT=XXXX

DB_TYPE=mysql
DB_HOST=localhost
DB_USERNAME=root
DB_PASSWORD=123456
DB_DATABASE=backstage
DB_PORT=3306
DB_LOGGING=true

SECRET=secret
           
import { ConfigModule, ConfigService } from 'nestjs-config';

@Module({
  imports: [
    // 配置加載配置檔案
    ConfigModule.load(path.resolve(__dirname, 'config', '**/!(*.d).{ts,js}'), {
      modifyConfigName: (name) => name.replace('.config', ''),
    }),
    // mysql的連接配接
    TypeOrmModule.forRootAsync({
      useFactory: async (config: ConfigService) => ({
        type: config.get('database.type'),
        host: config.get('database.host'),
        port: config.get('database.port'),
        username: config.get('database.username'),
        password: config.get('database.password'),
        database: config.get('database.database'),
        entities: [__dirname + '/**/*.entity{.ts,.js}'],
        subscribers: [__dirname + './../subscribers/*.subscriber{.ts,.js}'],
        logging: config.get('database.logging'),
        synchronize: false,
        timezone: '+08:00', // 東八區
      }),
      inject: [ConfigService],
    }),
    UserModule,
  ],
  controllers: [AppController],
  providers: [
    AppService,
  ],
})
           

ormconfig.js

{
  "type": process.env.DB_TYPE, // 選用的資料庫
  "host": process.env.DB_HOST, // 資料庫位址
  "port": Number(process.env.DB_PORT), // 資料庫端口
  "username": process.env.DB_USERNAME, // 資料庫使用者名
  "password": process.env.DB_PASSWORD, // 資料庫密碼
  "database": process.env.DB_DATABASE, // 資料庫
  "synchronize": true, // 是否同步true表示會自動将src/entity裡面定義的資料子產品同步到資料庫生成資料表(已經存在的表的時候再運作會報錯) 生産環境應改為false 通過指令行操作更新資料庫
  "dropSchema": true, // 删除資料庫中的表
  "logging": false, // 是否列印日志,執行sql語句時候輸出原生sql,也可以配置成一個數組["query", "error", "schema"]指定sql的執行類型
  "charset": "utf8mb4", // 編碼
  "timezone": "local", // 時區,預設本地,也可以寫"+8"
  "entityPrefix": "", // 給此資料庫連接配接上的所有表(或集合)加的字首。
  "entities": [ // 定義TypeORM需要查找的資料模型的,可以定義多個
      "src/modules/**/*.entity.{ts,js}"
  ],
  "migrations": [ // 資料遷移檔案生成的地方
      "src/migration/**/*.ts"
  ],
  "subscribers": [ // 訂閱(用的少)
      "src/subscribers/**/*.ts"
  ],
  "cli": { // 資料遷移工具使用的
      "entitiesDir": "src/modules",
      "migrationsDir": "src/migration",
      "subscribersDir": "src/subscriber"
  }
}
           

實作mysql typeorm 資料遷移的重點 個人學習

entities

migrations

的路徑要對應上 否則找不到檔案 mysql不會生成對應的

migration

"entities": [ 
      "src/modules/**/*.entity.{ts,js}"
  ],
  "migrations": [ 
      "src/migration/**/*.ts"
  ],
  "cli": {
      "entitiesDir": "src/modules",
      "migrationsDir": "src/migration"
  }
           

配置

package.json

"scripts": {
    "generate": "ts-node ./node_modules/typeorm/cli.js migration:generate -n Test",
    "db": "ts-node ./node_modules/typeorm/cli.js migration:run"
}
           

通過

npm run generate

會在設定的migrations路徑下生成對應的檔案

1646202649266-Test.ts

函數

up

為将要改變的資料庫的内容

函數

down

為恢複之前的資料庫的内容

import {MigrationInterface, QueryRunner} from "typeorm";

export class Test1646202649266 implements MigrationInterface {
    name = 'Test1646202649266'

    public async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`ALTER TABLE \`user\` DROP COLUMN \`grade\``);
        await queryRunner.query(`ALTER TABLE \`user\` CHANGE \`gender\` \`gender\` int NOT NULL COMMENT '性别' DEFAULT 0`);
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`ALTER TABLE \`user\` CHANGE \`gender\` \`gender\` int NOT NULL COMMENT '性别' DEFAULT '0'`);
        await queryRunner.query(`ALTER TABLE \`user\` ADD \`grade\` int NULL COMMENT '分數'`);
    }
}
           

通過

npm run db

執行生成的

migration

檔案 資料庫就會變更為新的對應

entity

字段格式

至此 資料遷移完成

mysql資料庫在service中使用

方式一: 通過

Entity

将資料庫注入到

Service

中 在方法中通過this.xxx 調用服務

import {
  BadRequestException,
  HttpStatus,
  Injectable,
  Logger,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { UserDto } from './user.dto';
import { UserEntity } from './user.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepository: Repository<UserEntity>,
  ) {}

  async createUser(userDto: UserDto) {
    const oldUser = await this.userRepository.find({
      name: userDto.name,
    });
    if (oldUser.length) {
      throw new BadRequestException('使用者已存在~');
    }
    userDto['hobby'] = userDto.hobby.toString();
    const createUser = await this.userRepository.create(userDto);
    const user = await this.userRepository.save(createUser);

    Logger.log('建立成功', `${user.name} 使用者建立成功`);
    return user;
  }
}

           

方式二:connection 參考connection 增删改查

async getPowerRoles(powerRolesDto): Promise<{ids: number[], keys: string[]}> {
    const list =  await getConnection()
      .createQueryBuilder(PowerRolesEntity, 'powerRoles')
      .where("powerRoles.isDel = 0")
      .andWhere("(powerRoles.roleId = :roleId)", { roleId: powerRolesDto.roleId })
      .getMany();

    const powerKeys = []
    for (const item of list) {
      const { powerId } = item
      const res = await this.powerRepository.findOne(powerId)
      if (res.isDel === 0) {
        // 未删除的才放入清單
        powerKeys.push(res.key)
      }
    }
           

繼續閱讀