基本上,我有一个由PHP (Laravel)构建的在线游戏。它的功能非常简单。当玩家装备一个物品时,它会检查是否同一类型的物品已经装备好了。如果没有相同类型的装备,它就会继续进行装备。
这是通过简单地将库存模型上装备的旗子设置为1来完成的。
if($alreadyequippeditem == false){
//equip current item
$inventory = \App\Inventory::find($item->pivot->id);
$inventory->equipped = 1;
$inventory->save();
}然而,如果一个人做得足够快,一个人可以同时装备两个(甚至更多)物品。根本上绕过了支票。
在我看来,这两个请求完全是由服务器同时处理的,它们在完全同时装备这些项,并且基本上绕过了检查。这可能解释了为什么两个项目可以装备,因为在请求运行时,它们不承认对方。我可能错了,但这是我唯一能想到的解释。
我怎么才能避开这一切?是否有办法限制它,以便同时只发送一个请求?我不记得当我用核心PHP和没有框架构建系统时遇到过这个问题,所以我不知道这是否是由laravel配置引起的。我知道我可能可以使用队列来绕过它(虽然我还没有深入研究它),但是我更愿意找到一个在站点范围内工作的解决方案,因为这个特定的问题影响到系统的许多领域。
发布于 2018-05-27 23:20:22
问题(种族状况)
你所经历的是一个经典的种族条件教科书的例子
竞争条件是当设备或系统试图同时执行两个或多个操作时发生的不良情况,但由于设备或系统的性质,操作必须按照正确的顺序进行。
示例修复了所有基本要素
幸运的是,这不是一个新问题,也不是一个很难解决的问题。特别是在使用Laravel时:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Inventory;
use App\Player;
use Request;
class BustRaceConditionsController extends Controller
{
public function EquipItem(Request $request)
{
\DB::beginTransaction();
$player = $player->where("id", $request->user()->player_id)->lockForUpdate()->first();
$success = true;
try {
/* some logic here to check if item is equiped or not */
if (itemIsEquiped()) {
$success = false;
} else {
/* lets equip the item, then save it, and then we need to commit it to the DB */
$player->itemEquip = $item;
$player->save();
\DB::commit();
}
} catch (\Exception $e) {
$success = false;
\DB::rollback();
}
return ['success' => $success];
}
}lockForUpdate()。这是为了确保在我的更改提交或失败之前,其他任何东西都不能读写,从而释放锁。我希望这能帮到你!
https://stackoverflow.com/questions/50556992
复制相似问题