我已经开发了一个基于AJAX的游戏,其中存在一个错误(非常偏远,但是在体积上它每小时至少发生一次)由于某种原因,两个请求几乎同时被发送到处理页面(最后一个我跟踪,请求的差异为.0001 ms)。在执行查询之前有一个检查,以确保它不会被执行两次,但由于差异太小,检查在下一个查询执行之前还没有完成。我很难过,我怎么能防止这种情况,因为它会在游戏中造成严重的问题。
为了更清楚,查询在游戏中开始新一轮,所以当它执行两次时,它会在同一时间开始2轮打破游戏,所以我需要能够停止脚本如果前一轮没有结束则执行,即使前一轮在.0001毫秒前开始。
答案 0 :(得分:3)
诀窍是使用原子更新语句来执行两个线程都无法成功的事情。它们不能同时成功,因此您只需执行以下查询:
UPDATE gameinfo SET round=round+1 WHERE round=1234
1234是当前正在进行的轮次。然后检查受影响的行数。如果线程影响零行,则它已经失败并且其他人事先做了它。我假设上面将在自己的事务中执行,因为自动提交已启用。
答案 1 :(得分:1)
所以你真正需要的是一个应用程序范围的互斥锁。 flock()sem_acquire()提供了这个 - 但仅限于系统级 - 如果应用程序分布在多个服务器上,则需要使用memcached或实现自己的套接字服务器来协调节点。
或者,您可以将数据库用作公共存储区域 - 例如使用MySQL获取表上的锁定,检查最后一次启动时的轮次,如果有必要,请更新行以说明新一轮开始(并记住这一点 - 然后解锁表格。继续....
下进行。
答案 2 :(得分:0)
锁定是这样做的一种方式,但在某些情况下更简单的方法是使您的请求具有幂等性。这只是意味着重复调用它与调用它的效果完全相同。
例如,您此刻的通话有效$round++;
明确重复拨打电话会造成麻烦。
但是你可以做$round=$newround;
这里重复的调用不会有任何影响,因为已经设置了回合,第二次调用只是将它设置为相同的值。