阻止 N+1 雪崩:强制执行 Laravel Strict Mode

N+1 查询问题会严重破坏数据库性能。当你获取一组记录并循环遍历它们以访问关联关系时,就会发生这种情况。因为你忘记了提前加载该关联关系。

假设你在仪表板上显示 50 张发票。你通过循环来显示客户名称。但你忘记使用 with 方法。Eloquent 会为发票运行 1 个查询,然后为每个客户分别运行 50 个查询。

在本地开发环境中,51 个查询仅需 10 毫秒,你根本察觉不到。但在生产环境中,高并发流量会将此问题演变成一场雪崩。它会耗尽你的数据库连接池并导致服务器崩溃。

你不能仅仅依赖代码审查。你需要一种架构层面的防护机制。

Laravel 提供了 Strict Mode 来解决这个问题。你可以在应用层使用 preventLazyLoading。Laravel 会监控你的数据库关联关系。如果在本地开发或测试期间检测到延迟加载(lazy load),它会抛出一个异常。这会迫使你立即修复代码。

如何设置:

在你的 AppServiceProvider 中配置安全机制。请针对本地和测试环境进行此操作。在生产环境中,你应该记录错误日志,而不是让应用崩溃。

在你的 boot 方法中使用以下三个设置:

  • Model::preventLazyLoading: 阻止 N+1 查询。
  • Model::preventSilentlyDiscardingAttributes: 阻止批量赋值失败。
  • Model::preventAccessingMissingAttributes: 防止因缺失关联关系导致的内存泄漏。

对于生产环境,请使用 handleLazyLoadingViolationUsing。这允许你将违规行为记录到 Slack 或日志服务中。这样你可以在不破坏用户体验的情况下获得问题的可见性。

强制执行 Strict Mode 将优化工作提前到了流水线的起始阶段。N+1 查询无法通过你的测试。你的代码库将保持优化状态。你的数据库将保持高效。

Source: https://dev.to/iprajapatiparesh/stop-n1-avalanches-enforce-laravel-strict-mode-2oop