我的API中有一条路由,例如,可以将其称为/ users /:userId / updateBalance.此路由将获取用户当前余额,添加来自请求的任何内容,然后使用新计算的余额更新余额.这样的请求每隔30分钟就会针对特定用户进入服务器,因此直到最近,我还认为并发问题是不可能的.
最终发生的情况是,某个地方的已发送请求失败,并且仅在30分钟后(大约在另一个请求的一秒钟之内)再次发送.结果是,正如我在数据库中看到的那样,这两个请求都从数据库中获取了相同的余额,并且都添加了各自的金额.本质上,第二个请求实际上读取了一个过时的余额,因为通常它应该在请求1执行后执行.
为了更清楚地给出一个数值示例,假设请求1将2美元添加到余额中,请求2则添加5美元,而用户的余额为10美元.如果请求并行执行,则根据请求1或请求2首先完成,用户余额将分别为$12或$15,因为两个请求都从DB提取了$10的余额.但是,显然预期的行为是我们希望执行请求1,将用户余额更新为$12,然后请求2执行并将余额从$12更新为$17.
为了更好地了解此过程的整体执行情况:接收了请求,调用了一个函数,该函数必须等待DB的余额,然后该函数计算新的余额并更新db,然后执行完成了.
因此,我对此有一些疑问.第一个是,节点在等待异步请求(如MySQL数据库读取)时如何处理传入的请求.根据我观察到的结果,我假设当第一个请求等待数据库时,第二个请求可以开始处理吗?否则,我不确定在节点等单线程环境中如何经历这种异步行为.
其次,我该如何控制和预防它.我本想使用带有forUpdate锁的MySQL事务,但事实证明,由于当前编写代码的方式,这似乎是不可能的.有没有办法告诉节点某个代码块不能“并行”执行?还是其他选择?