nestjs学习 - 数据库连接、创建表

0 阅读3分钟

了解ERD图,如何设计数据库表结构;

一、基础知识

  • 表头-字段

  • 主键

    唯一标识; 一般是 ID, 也可以是两列,ID & UserName 成为联合主键;

    外键:关联两个表

  • 关系型,表与表的关系

    一对一、一对多、多对多

关系型

MySQL、Oracle、SQL Server、Access、SQLite、postgreSQL

ERD设计:Navicat,dbdesigner,QuickDBD

免费数据库设计大全

非关系型

MongoDB、Redis、Hbase、Memcache

二、nestjs中如何配置

1. 依赖安装

nest 中使用官方推荐的 ORM 工具 TypeORM,首先下载相关依赖

npm install --save @nestjs/typeorm typeorm mysql2

2. 配置

dir.png

app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
​
import { DatabaseModule } from './shared/database/database.module';
import config from '~/config';
​
import { AppController } from './app.controller';
import { AppService } from './app.service';
​
@Module({
  imports: [
    ConfigModule.forRoot({
      // 全局配置
      isGlobal: true,
      // 展开环境变量,将环境变量转换为对象;eg: DB_HOST=localhost -> { DB_HOST: 'localhost' }
      expandVariables: true,
      // 环境变量文件
      envFilePath: ['.env.local', `.env.${process.env.NODE_ENV}`, '.env'],
      // 加载配置
      load: [...Object.values(config)],
    }),
    DatabaseModule,
  ],
  // 。。。
})
export class AppModule {}

database.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigService } from '@nestjs/config';
import { dbRegToken, IDatabaseConfig } from '~/config/database.config';
// import { DataSourceOptions } from 'typeorm';
​
@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => {
        const dataSourceOptions = configService.get<IDatabaseConfig>(dbRegToken)
        return {
          ...dataSourceOptions
        }
      },
    }),
  ],
  exports: [],
})
export class DatabaseModule {}

config文件夹下文件:

index.ts

import { DatabaseConfig } from './database.config'export default {
    database: DatabaseConfig,
}

database.config.ts

import { ConfigType, registerAs } from '@nestjs/config'
import { DataSourceOptions } from 'typeorm'import dotenv from 'dotenv'
​
dotenv.config({ path: `.env.${process.env.NODE_ENV}` })
​
/**
 * @description 数据源配置
 */
const dataSourceOptions: DataSourceOptions = {
  type: 'mysql',
  host: process.env.DB_HOST,
  port: parseInt(process.env.DB_PORT),
  username: process.env.DB_USERNAME,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
}
export const dbRegToken = 'database'
​
​
/**
 * @nestjs/config 里的这两个是做“类型安全配置”的核心工具:
​
registerAs:给一组配置命名并注册
​
你用它把配置包装成一个命名空间,例如 registerAs('database', () => ({ ... }))
这样配置键就变成 database.xxx,方便模块化管理
常用于 src/config/*.config.ts 这种文件里
ConfigType:从 registerAs 的配置工厂中推导 TS 类型
​
它是一个泛型工具类型:ConfigType<typeof databaseConfig>
可以拿到 databaseConfig 返回对象的精确类型,避免手写接口
常配合 @Inject(databaseConfig.KEY) 注入时使用,让 config.host、config.port 都有类型提示和检查
 */
export const DatabaseConfig = registerAs(
  dbRegToken,
  (): DataSourceOptions => dataSourceOptions,
)
​
export type IDatabaseConfig = ConfigType<typeof DatabaseConfig>

.env.development

# Node 环境:production 里建议开启严格配置
NODE_ENV=development
​
# MySQL 连接信息
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=12345678
DB_NAME=test_db

Tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
     "target": "ES2021",
    // .....
    // 如下两项配置需要特别注意,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
  },
}

这两个配置项是 TypeScript 项目中解决模块互操作性问题的关键,尤其是在混用 ES 模块(ESM)和 CommonJS 模块时。它们通常一起开启,以获得更统一、更顺畅的开发体验。

它们共同解决了“用现代的 import 语法去引入旧的 CommonJS 模块”时可能出现的各种不兼容问题。

三、创建一个表(实体)

通过命令行创建一个 users 模块:

nest g res users

到指定的目录下执行以上命令,会自动生成一个 REST API 风格的代码模版;

entity.png

执行以上命令会生成上图左下角的目录结构,其中 user.entity.ts 则为实体文件;

用户 实体代码如下 user.entity.ts

import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
​
@Entity('users')
export class UserEntity {
  @PrimaryGeneratedColumn()
  id: number;
  
  @Column()
  name: string;
​
  @Column()
  password: string;
​
  // nullable 设置为 true,表示该字段可以为空
  @Column({ nullable: true })
  email: string;
​
  @Column({ nullable: true })
  phone: string;
​
  @CreateDateColumn({ name: 'created_at' })
  createdAt: Date;
​
  @UpdateDateColumn({ name: 'updated_at' })
  updatedAt: Date;
}

@Column({ nullable: true }) 这行需要注意,如果字段在创建时不需要(可选),必须设置 nullable: true,否则会报错,参数没有默认值,类似:

Error creating user entity: QueryFailedError: Field 'email' doesn't have a default value

users.module.ts 中引入实体

import { UserEntity } from './entities/user.entity';
​
@Module({
  imports: [TypeOrmModule.forFeature([UserEntity])],
  // ...  
  
  // 如果想在导入了 TypeOrmModule.forFeature 的模块之外使用仓库,您需要重新导出由它生成的提供者。 您可以通过导出整个模块来实现,像这样:
  exports: [TypeOrmModule]
})

以上代码配置完成后,启动服务不报错的话就会看到数据库里面自动新增了一个表名为 users,相关字段信息就是我们实体里面配置的字段;