Nodejs+Sequelize(Mysql)跨请求读写异步操作竞态问题求解
Node.js Sequelize MySQL跨请求读写竞态解决方案
你提到的跨请求场景下普通事务无效的判断是正确的:不同请求的事务相互独立,没有加锁的普通事务仅能保证单请求内的操作原子性,无法阻挡多个请求同时读到空记录后重复写入的竞态问题。
以下是不同场景下的可行解决方案:
方案1:数据库唯一约束(优先推荐)
该方案是性能最高、逻辑最简洁、可靠性最强的解法,完全避免竞态的核心是利用数据库全局生效的原子性唯一校验规则,不受请求上下文限制。
操作步骤:- 匹配你的查询条件,给
conversations表加联合唯一索引:如果你查询时的createdAt LIKE :time是按天匹配,可新增冗余字段created_date存储DATE类型的日期,索引字段为context、phoneNumber、created_date,建索引SQL:ALTER TABLE conversations ADD UNIQUE KEY uniq_ctx_phone_created (context, phoneNumber, created_date); - 代码逻辑改为先尝试插入,捕获唯一约束异常来判断是否已存在,示例代码:
try { await conversationsModel.create({ phoneNumber: to.phoneNumber, context: "team", displayName: "xxx", externalId, message, type: "media", created_date: new Date().toISOString().slice(0,10) // 匹配你的时间过滤规则调整 }); return 'X'; } catch (err) { // MySQL唯一约束冲突错误码为ER_DUP_ENTRY if (err.original?.code === 'ER_DUP_ENTRY' || err.name === 'SequelizeUniqueConstraintError') { return 'Y'; } throw err; }- 匹配你的查询条件,给
方案2:带排他锁的事务(适合无法加唯一索引的场景)
给查询操作加FOR UPDATE排他锁,事务开启后第一个请求的查询会锁定对应范围的行/间隙,后续同条件的查询会阻塞到第一个事务提交/回滚后再执行,从数据库层面避免幻读。
示例代码:const transaction = await sequelize.transaction({ isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED }); try { const existRecords = await sequelize.query( 'SELECT xxx FROM conversations where context="yyy" AND phoneNumber=:phoneNumber AND createdAt LIKE :time FOR UPDATE', { replacements: { phoneNumber: to.phoneNumber, time: yourTimeParameter }, type: Sequelize.QueryTypes.SELECT, transaction } ); if (existRecords.length) { await transaction.commit(); return 'Y'; } await conversationsModel.create({ phoneNumber: to.phoneNumber, context: "team", displayName: "xxx", externalId, message, type: "media" }, { transaction }); await transaction.commit(); return 'X'; } catch (err) { await transaction.rollback(); throw err; }注意事项:该方案需要控制事务执行时长,避免长事务导致大量请求阻塞。
方案3:分布式锁(适合多实例部署的附加防护)
可以基于Redis实现分布式锁,锁的key由查询条件拼接而成(如conversation:team:${to.phoneNumber}:${yourTimeParameter}),只有拿到锁的请求才可以执行查+写逻辑,执行完成后释放锁。该方案容错性低于数据库唯一约束,建议作为前两种方案的补充使用。
内容的提问来源于stack exchange,提问作者Eliran Suisa
相关产品推荐
相关产品推荐

