Sequelize中BelongsToSetAssociationMixin调用后永久挂起的解决方法
Sequelize关联RefreshToken与Account时执行
setAccount挂起问题 尝试用Sequelize在PostgreSQL中创建与指定Account关联的RefreshToken,但调用setAccount时会挂起数分钟,无错误信息,仅Jest测试在240秒后超时。
表关系定义
Account.hasMany(RefreshToken, { as: "refresh_token_owner", foreignKey: "refresh_token_owner_id", }); RefreshToken.belongsTo(Account, { as: "refresh_token", foreignKey: "refresh_token_id" });
RefreshToken的Mixin定义
import { Account, AccountId } from "./Account"; export class RefreshToken extends Model<RefreshTokenAttributes, RefreshTokenCreationAttributes> implements RefreshTokenAttributes { getAccount!: Sequelize.BelongsToGetAssociationMixin<Account>; setAccount!: Sequelize.BelongsToSetAssociationMixin<Account, AccountId>; createAccount!: Sequelize.BelongsToCreateAssociationMixin<Account>; static initModel(sequelize: S): typeof RefreshToken { // 省略部分代码 } }
业务代码
public createRefreshToken = async (id: number, token: string, expires: Date, createdByIp: string) => { const associatedAcct: Account | null = await this.accountDAO.getAccountById(id); if (associatedAcct === null) throw Error("Account not found"); const rt: RefreshToken = await RefreshToken.create({ token, expires, createdByIp, isActive: true, }); console.log(rt, "38rm"); // 正常打印 rt.setAccount(associatedAcct); console.log("account set", "40rm"); // 数分钟后仍不打印 return rt; };
排查过程
- edit3:按建议开启Sequelize日志,但未看到预期SQL语句
import { TEST_DB_HOST, TEST_DB_NAME, TEST_DB_PASSWORD, TEST_DB_PORT, TEST_DB_USER } from "../config"; export const testDatabase = new Sequelize({ dialect: "postgres", host: TEST_DB_HOST, port: TEST_DB_PORT, database: TEST_DB_NAME, username: TEST_DB_USER, password: TEST_DB_PASSWORD, logging: (...msg) => console.log(msg), });
- edit4:怀疑初始化错误,尝试按文档**Option 3: 单独传入参数(其他方言)**修改初始化方式
// const testDatabase = new Sequelize({ // dialect: "postgres", // host: TEST_DB_HOST, // port: TEST_DB_PORT, // database: TEST_DB_NAME, // username: TEST_DB_USER, // password: TEST_DB_PASSWORD, // // logging: console.log,// 无效 // }); const testDatabase = new Sequelize("postgres", "postgres", "postgres", { host: TEST_DB_HOST, dialect: "postgres", logging: console.log, });
问题根源与解决办法
关联定义不匹配
Account.hasMany的别名是refresh_token_owner,但RefreshToken.belongsTo的别名是refresh_token,且外键设置错误——belongsTo的外键应指向Account的关联字段refresh_token_owner_id,而非refresh_token_id。别名和外键不匹配会导致Sequelize无法生成正确的关联SQL,进而引发挂起。
修正后的关联定义:RefreshToken.belongsTo(Account, { as: "refresh_token_owner", // 与hasMany的别名保持一致 foreignKey: "refresh_token_owner_id" // 对应hasMany的外键 });异步方法未等待
setAccount是异步方法,必须添加await等待执行完成,否则代码会继续执行,但关联操作在后台阻塞,最终导致测试超时。
修正后的业务代码片段:await rt.setAccount(associatedAcct);日志未生效的排查
- 确保所有模型初始化时使用的是同一个
testDatabase实例,若模型关联了其他Sequelize实例,日志配置不会生效。 - 简化日志配置,直接设置
logging: console.log测试是否能输出SQL语句。
- 确保所有模型初始化时使用的是同一个
内容的提问来源于stack exchange,提问作者plutownium
相关产品推荐
相关产品推荐

