mysql - NestJS/TypeORM。TypeORM 不更新数据库中的实体,而是使用旧的缓存实体
问题描述
我整天都在尝试将实体保存到 MySQL 数据库中遇到巨大的困难。我正在使用 NestJS 和 TypeORM。
教师实体.ts
import { BeforeInsert, Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import * as bcrypt from 'bcrypt';
import { bcryptConstants } from 'src/bcrypt/bcrypt.constants';
@Entity({'name': 'teacher'})
export class Teacher {
@PrimaryGeneratedColumn()
id: number;
@Column()
username: string;
@Column()
email: string;
@Column()
password: string;
@BeforeInsert()
async hashPassword(): Promise<void> {
const salt = await bcrypt.genSalt(bcryptConstants.saltRounds);
const hash = await bcrypt.hash(this.password, salt);
this.password = hash;
}
}
app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { SubjectsController } from './subjects/subjects.controller';
import { SubjectService } from './subjects/subject/subject.service'
import { TeacherModule } from './teacher/teacher.module';
import { AuthModule } from './auth/auth.module';
@Module({
imports: [ TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'test',
entities: ["dist/**/*.entity{.ts,.js}"],
synchronize: true,
logging: true
}), TeacherModule, AuthModule],
controllers: [AppController, SubjectsController],
providers: [AppService, SubjectService],
})
export class AppModule { }
这是错误:
+10767ms
query: START TRANSACTION
query: INSERT INTO `teacher`(`id`, `username`, `email`, `password`) VALUES (DEFAULT, ?, ?, ?) -- PARAMETERS: ["babbb","babbb","$2b$10$CMyzTJU6g1gJX2eO8Ulleez.LKo1XTCHvVKeUFKJS2FF9bwXivNR."]
query: COMMIT
+120008ms
query: START TRANSACTION
query: INSERT INTO `teacher`(`id`, `username`, `email`, `password`) VALUES (DEFAULT, ?, ?, ?) -- PARAMETERS: ["babbb","babbb","$2b$10$XU8QNxCRL4Ole2OxWkInruLogt0/e/SAfJoAhw.dBbad3MBb5D.iS"]
query failed: INSERT INTO `teacher`(`id`, `username`, `email`, `password`) VALUES (DEFAULT, ?, ?, ?) -- PARAMETERS: ["babbb","babbb","$2b$10$XU8QNxCRL4Ole2OxWkInruLogt0/e/SAfJoAhw.dBbad3MBb5D.iS"]
error: Error: Duplicate entry 'babbb' for key 'teacher.IDX_76fd0cda3fc6719d3109237c72'
{
code: 'ER_DUP_ENTRY',
errno: 1062,
sqlState: '23000',
sqlMessage: "Duplicate entry 'babbb' for key 'teacher.IDX_76fd0cda3fc6719d3109237c72'"
}
query: ROLLBACK
[Nest] 5360 - 03/06/2021, 9:59:03 PM [ExceptionsHandler] Duplicate entry 'babbb' for key 'teacher.IDX_76fd0cda3fc6719d3109237c72' +192ms
该实体实际上已保存在数据库中,但 NestJS 需要一整分钟才能完成此任务并返回响应。我正在使用等待此响应的 Angular,以便在注册为教师后将用户重定向到登录页面。在发送发布请求以在数据库中创建教师后,我只收到状态 500 的错误。
mysql表
id username email password
1 user12 user $2b$10$kYZ3F2Hv2MkuvQJIBUsK5Ogq4PHQPLiOBp1t9x3.psOwL984/KTQe
4 babbb babbb $2b$10$CMyzTJU6g1gJX2eO8Ulleez.LKo1XTCHvVKeUFKJS2FF9bwXivNR.
我插入了 2 个条目,但由于某种原因,它跳过了 ID 2 和 3 的保存。
我尝试使用“uuid”作为这样的 ID:
@PrimaryGeneratedColumn("uiid")
id: string;
但是,当我清楚地将列定义为字符串时,它仍然给我一个错误,即生成的 uuid 字符串太长而无法保存为整数值。
欢迎任何建议!
更新
TypeORM 为我的列“用户名”和“电子邮件”添加了一个唯一索引,即使我没有在“@Column()”中指定它。
query: SELECT VERSION() AS `version`
query: SELECT * FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = 'test' AND `TABLE_NAME` = 'typeorm_metadata'
query: ALTER TABLE `teacher` CHANGE `username` `username` varchar(255) NOT NULL
query: ALTER TABLE `teacher` ADD UNIQUE INDEX `IDX_76fd0cda3fc6719d3109237c72` (`username`)
query: ALTER TABLE `teacher` CHANGE `email` `email` varchar(255) NOT NULL
query: ALTER TABLE `teacher` ADD UNIQUE INDEX `IDX_00634394dce7677d531749ed8e` (`email`)
query: COMMIT
即使我使用“@Column({ unique: false})”,它仍然会为它们添加唯一索引。我的其他表没有这个问题,只有这个。
第二次更新
好吧,我肯定知道现在的问题是什么。TypeORM 不能正确同步我的实体,更具体地说是“老师”实体。当我向“教师”表添加新列时,它会正确更新。当我从我的代码中删除“电子邮件”、“密码”、“用户名”列时,它们仍在表中,我无法更改这些列。我不知道这是否与某些缓存问题有关。我的同步“同步:真”已打开。
解决方案
您需要指定@PrimaryGeneratedColumn
生成UUID而不是UIID或 Integer,因为您尝试过。
# Not like this
@PrimaryGeneratedColumn("uiid")
id: string;
# Like this
@PrimaryGeneratedColumn("uuid")
id: string;
以下是指定UUID列类型的实体的编写方式。
@Entity({ name: 'teacher' })
export class Teacher {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
username: string;
@Column()
email: string;
@Column()
password: string;
@BeforeInsert()
async hashPassword(): Promise<void> {
const salt = await bcrypt.genSalt(bcryptConstants.saltRounds);
const hash = await bcrypt.hash(this.password, salt);
this.password = hash;
}
}
关于保存时的延迟,Bcrypt 正在对您的密码进行哈希处理,通常需要很长时间。
推荐阅读
- python - 使用 Pandas 将分类列拆分为列
- c# - 带有刷新令牌的 ASP.NET OWIN OAUTH2.0
- java - 如何在合格的服务上动态调用方法?
- python - 使用 elemmatch 和过滤器执行 pymongo 查询
- c# - C# WPF 与 CLR 抛出异常
- json - 动态标记和 infoWindow Google Maps API 使用 Google App Engine 通过 JSON 文件解析
- java - 在波纹管项目的顶部项目上显示计算结果
- javascript - 如何在不使用 axios 崩溃功能的情况下处理错误?
- http - IdHttpServer 不提供文件
- python - 如何在推理期间清除变量以释放 ram 内存?