React数据库更新异常:JWT认证转账时用户余额未同步至数据库
转账余额未同步数据库的解决方法
问题根源分析
- 关联账单未单独保存:你修改了
user.bills[0].amount后仅调用user.save(),但user.bills是通过populate获取的关联Bill文档,修改关联文档的属性后,必须单独保存该Bill实例,否则数据库不会同步更新。 - 异步回调错误捕获失效:
jwt.verify的异步回调中使用async/await,外层try/catch无法捕获回调内的错误,导致部分异常无法被处理。 - 缺少关键校验:未检查转账金额合法性、用户余额是否充足,存在逻辑漏洞。
- 浮点精度隐患:
parseFloat处理金额易引发精度误差,比如0.1 + 0.2的计算结果不符合预期。
修复后的代码
const SendMoney = async (req, res) => { try { const { token } = req.cookies; const { amount, billnumber } = req.body; // 改用Promise封装jwt.verify,确保try/catch能捕获所有错误 const decodedToken = await new Promise((resolve, reject) => { jwt.verify(token, process.env.JWT_SECRET, {}, (err, decoded) => { err ? reject(err) : resolve(decoded); }); }); const user = await User.findById(decodedToken.id).populate("bills"); const targetBill = await Bill.findOne({ billnumber }); if (!targetBill) { return res.json({ error: "无效的账单号!" }); } const transferAmount = Number(amount); // 校验金额是否合法 if (isNaN(transferAmount) || transferAmount <= 0) { return res.json({ error: "金额必须是正数!" }); } const userBill = user.bills[0]; if (!userBill) { return res.json({ error: "用户无可用账单!" }); } // 校验余额是否充足 if (userBill.amount < transferAmount) { return res.json({ error: "余额不足!" }); } // 执行余额变更 targetBill.amount += transferAmount; userBill.amount -= transferAmount; // 并行保存两个账单的修改,提升效率 await Promise.all([targetBill.save(), userBill.save()]); // 返回数据库中最新的用户数据 return res.json({ success: "转账成功!", user: await User.findById(decodedToken.id).populate("bills"), }); } catch (error) { console.error(error); return res.status(500).json({ error: "服务器错误!", }); } };
核心修复说明
- 保存关联账单:修改用户账单余额后,调用
userBill.save()同步到数据库,配合Promise.all并行处理两个账单的保存操作。 - 统一错误捕获:用Promise封装
jwt.verify,让所有异步逻辑都处于外层try/catch的覆盖范围内,避免遗漏错误。 - 完善校验逻辑:新增金额合法性、余额充足性检查,防止非法转账操作。
- 优化金额处理:用
Number替代parseFloat减少精度问题,更严谨的方案是将金额以“分”为单位存储(整数类型),彻底避免浮点误差。 - 返回最新数据:重新查询用户并关联账单,确保响应内容是数据库的最新状态。
内容的提问来源于stack exchange,提问作者Bence Duba
相关产品推荐
相关产品推荐

