Laravel更新订单商品后API返回旧数据 响应滞后一次请求问题
问题现象
发起订单商品更新请求时,数据库数据已更新完成,但API响应存在固定一次的数据滞后:原订单总价100,提交更新后预期为150,本次接口返回、以及更新后立即查询拿到的仍是旧值100;再次提交更新将总价调整为200时,返回值才是上一次更新后的150,数据始终比数据库实际值慢一步,必须发起下一次请求才能拿到本次更新的正确结果。
问题涉及的更新代码如下:
public function updateProducts(AdminUpdateOrderRequest $request, $id) { $orderValidated = $request->validated(); $order = Order::findOrFail($id); if (isset($orderValidated['products'])) { $order->products()->sync($orderValidated['products']); } DB::table('order_product')->where('order_id', $order->id) ->update([ 'total_buy_price' => DB::raw('order_product.quantity * (select converted_buy_price from products where id = order_product.product_id)'), 'total_selling_price' => DB::raw('order_product.quantity * (select converted_selling_price from products where id = order_product.product_id) ') ]); DB::table('orders')->where('id', $order->id)->update([ 'cost_price' => DB::raw('(select SUM(order_product.total_buy_price) from order_product where order_product.order_id = ' . $order->id . ')'), 'total_price' => DB::raw('(select SUM(order_product.total_selling_price) from order_product where order_product.order_id = ' . $order->id . ')'), 'remaining' => DB::raw('(select SUM(order_product.total_buy_price) from order_product where order_product.order_id = ' . $order->id . ' - ' . $order->payments->sum('amount') . ')'), 'products_count' => DB::raw('(select SUM(quantity) from order_product where order_product.order_id = ' . $order->id . ')') ]); DB::table('packages')->update([ 'selling' => DB::raw('(select SUM(orders.total_price) from orders where orders.package_id = packages.id)'), 'amount' => DB::raw('(select SUM(orders.total_price) from orders where orders.package_id = packages.id)'), 'cost' => DB::raw('(select SUM(orders.cost_price) from orders where orders.package_id = packages.id)'), ]); return OrderResource::make($order)->additional([ 'success' => true, ]); }
故障原因
核心问题是Eloquent模型的内存数据和数据库实际数据不同步:
- 代码开头通过
Order::findOrFail($id)取出的$order是存在于当前请求内存中的模型实例,存储的是查询当下的旧属性值 - 后续所有价格、统计字段的更新,都是通过
DB::table()直接执行SQL操作数据库,全程没有修改内存中$order实例的属性 - 最终返回响应时,
OrderResource读取的是内存里的旧$order数据,自然返回更新前的值。下一次请求进入时会重新从数据库查询,就会拿到上一次更新的结果,表现为固定滞后一次。
额外隐藏bug:remaining字段的SQL括号位置错误,当前写法会先计算order_id = 订单ID - 已支付金额的查询条件,会导致统计结果完全错误。
修复方法
所有更新操作执行完成后,刷新模型的内存数据,再传给资源返回即可,同时修正remaining字段的SQL逻辑。
两种可选实现方式:
- 调用模型自带的
refresh()方法刷新属性,同时预加载资源需要的关联关系避免N+1查询:
// 原有更新逻辑中修正remaining字段的SQL括号问题 $paidTotal = $order->payments->sum('amount'); DB::table('orders')->where('id', $order->id)->update([ 'cost_price' => DB::raw('(select SUM(order_product.total_buy_price) from order_product where order_product.order_id = ' . $order->id . ')'), 'total_price' => DB::raw('(select SUM(order_product.total_selling_price) from order_product where order_product.order_id = ' . $order->id . ')'), // 先计算商品总价,再减去已支付金额 'remaining' => DB::raw('(select SUM(order_product.total_buy_price) from order_product where order_product.order_id = ' . $order->id . ') - ' . $paidTotal), 'products_count' => DB::raw('(select SUM(quantity) from order_product where order_product.order_id = ' . $order->id . ')') ]); // packages表更新逻辑保持不变 // 刷新模型数据,加载关联 $order->refresh(); $order->load(['products', 'payments']); return OrderResource::make($order)->additional([ 'success' => true, ]);
- 所有更新完成后,重新从数据库查询最新的订单实例,效果完全一致:
// 所有更新逻辑执行完成后 $freshOrder = Order::with(['products', 'payments'])->findOrFail($id); return OrderResource::make($freshOrder)->additional([ 'success' => true, ]);
内容的提问来源于stack exchange,提问作者ayaabdo
相关产品推荐
相关产品推荐

