You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel:更新模型触发观察者时出现内存耗尽问题

问题排查与解决方案:内存耗尽源于模型观察者无限循环更新

核心问题分析

修改expected_start_date或expected_end_date时触发内存耗尽,本质是无限循环触发模型更新事件:

  1. 控制器调用$mymodel->update()触发updated观察者事件
  2. 观察者检测到日期字段变更,调用updateDurationInMonths()
  3. 该方法内调用$this->save()再次触发updated事件
  4. 循环往复直到内存耗尽

解决方案:打破事件循环

最直接的修复是使用Laravel提供的saveQuietly()方法,保存模型时不触发任何观察者/事件,彻底打破循环。同时补充边界值判断,避免日期为空时的Carbon解析错误:

修改MyModel.php中的updateDurationInMonths方法

public function updateDurationInMonths()
{
    // 处理日期为空的边界情况
    if (empty($this->expected_start_date) || empty($this->expected_end_date)) {
        $this->duration_in_months = null;
        $this->saveQuietly();
        return;
    }

    $startDate = Carbon::parse($this->expected_start_date);
    $endDate = Carbon::parse($this->expected_end_date);
    $this->duration_in_months = $startDate->diffInMonths($endDate);
    // 用saveQuietly替代save,不触发观察者事件
    $this->saveQuietly();
}

可选优化方案

如果不想使用saveQuietly(),也可以在观察者中增加判断,跳过duration_in_months字段更新时的触发逻辑:

修改MyModelObserver.php的updated方法

public function updated(MyModel $mymodel): void
{
    // 仅当日期字段变更且duration_in_months未变更时执行
    if (
        ($mymodel->isDirty('expected_start_date') || $mymodel->isDirty('expected_end_date'))
        && !$mymodel->isDirty('duration_in_months')
    ) {
        $mymodel->updateDurationInMonths();
    }
}

额外前端优化建议

Inertia路由可以使用Laravel生成的命名路由,避免硬编码URL:

const postMyModelEdit = () => {
    editMode.value = false;
    // 使用命名路由,更健壮
    router.patch(route('mymodels.update', props.mymodel.id), {
        name: props.mymodel.name,
        description: props.mymodel.description,
        expected_start_date: props.mymodel.expected_start_date,
        expected_end_date: props.mymodel.expected_end_date,
    });
}

内容的提问来源于stack exchange,提问作者Cornel Verster

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 01:52:04