前提假设本地的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)
}
}