如何处理酒店房间API并发请求,避免重复分配房间?
解决并发请求下酒店房间重复分配的问题
你的核心问题是并发场景下房间被重复分配,根源在于代码存在语法错误,同时未充分利用MongoDB原子操作的特性来保障可靠性,以下是具体修复方案:
1. 修复语法错误
你的$set字段中,isBusy: true后缺少逗号,会导致更新操作失效——房间的isBusy状态根本没被修改,所有请求都会反复匹配到同一个空闲房间:
// 错误写法 $set:{ isBusy: true customer: request.body.customer_id } // 正确写法(添加逗号) $set:{ isBusy: true, customer: request.body.customer_id }
2. 确保findOneAndUpdate的原子性与正确性
findOneAndUpdate本身是MongoDB的原子操作,但需明确指定选项,保证只更新第一个匹配的空闲房间,并返回正确的文档:
const db = await ConnectToDatabase(process.env.MONGODB_URI); const collection2 = db.collection('rooms'); // 指定returnDocument: 'before' 返回更新前的房间信息,upsert: false 避免创建新文档 const result = await collection2.findOneAndUpdate( { isBusy: false }, { $set: { isBusy: true, customer: request.body.customer_id } }, { returnDocument: 'before', upsert: false } ); if (!result) { return response.status(200).json({ status: "FAIL", msg: "No available rooms" }); } return response.status(200).json({ status: "SUCCESS", room: result.room_number });
3. 额外优化建议
- 添加索引:给
isBusy字段创建单键索引,提升并发下的查询效率,减少请求排队时间:// 集合初始化时执行一次即可 await collection2.createIndex({ isBusy: 1 }); - 使用写关注:如果需要更高的数据一致性,可指定
writeConcern选项,确保写入操作被MongoDB集群多数节点确认:const result = await collection2.findOneAndUpdate( { isBusy: false }, { $set: { isBusy: true, customer: request.body.customer_id } }, { returnDocument: 'before', upsert: false, writeConcern: { w: 'majority' } } ); - 统一用POST请求:分配房间是修改状态的写操作,GET请求是幂等的,建议只使用POST处理房间分配,避免浏览器或CDN重复发送GET请求导致意外。
内容的提问来源于stack exchange,提问作者SrMilton
相关产品推荐
相关产品推荐

