
在 laravel 中,直接链式调用 `where()` 和 `orwhere()` 会导致意外的 sql 优先级问题(如 `and` 被 `or` 短路),从而破坏原有查询条件;必须通过闭包逻辑分组确保搜索条件整体作为子条件与主条件(如 `airline_id`)进行 `and` 连接。
当你编写如下查询时:
Product::with('airline')
->where('airline_id', $request->airline_id)
->select('id','name','code')
->where("name","LIKE","%{$request->search}%")
->orWhere("code","LIKE","%{$request->search}%")
->limit(5)
->get();Laravel 会生成类似以下的原始 SQL(无括号分组):
WHERE airline_id = ? AND name LIKE ? OR code LIKE ?
由于 SQL 中 AND 的优先级高于 OR,该语句实际等价于:
WHERE (airline_id = ? AND name LIKE ?) OR code LIKE ?
这意味着:只要产品代码匹配搜索词,无论 airline_id 是否一致,都会被查出——这正是你看到“其他航司产品混入”的根本原因。
✅ 正确解法是使用 where() 闭包进行逻辑分组,将 name 或 code 的模糊匹配封装为一个原子条件单元,使其整体与 airline_id 条件以 AND 关系组合:
Product::with('airline')
->select('id', 'name', 'code')
->where('airline_id', $request->airline_id)
->where(function ($query) use ($request) {
$query->where('name', 'LIKE', "%{$request->search}%")
->orWhere('code', 'LIKE', "%{$request->search}%");
})
->limit(5)
->get();生成的 SQL 将变为:
WHERE airline_id = ? AND (name LIKE ? OR code LIKE ?)
✅ 完全符合业务预期:仅返回指定航司下、名称或编码匹配搜索词的产品。
? 额外建议与注意事项:
- 安全防护:务必对 $request->search 做非空校验与基础过滤(如 trim()、strlen() > 0),避免空字符串导致 LIKE '%%' 全表扫描;
- 性能优化:若数据量大,建议为 airline_id、name 和 code 字段建立联合索引(如 INDEX(airline_id, name, code))或至少确保 airline_id 有独立索引;
- 扩展性写法:如后续需支持更多字段(如 description),可统一在闭包内追加 orWhere(),逻辑依然清晰可控;
- Eloquent 替代方案:也可使用 when() 实现条件式构建,增强可读性(尤其在多条件动态场景中):
->when($request->filled('search'), function ($query) use ($request) {
return $query->where(function ($q) use ($request) {
$q->where('name', 'LIKE', "%{$request->search}%")
->orWhere('code', 'LIKE', "%{$request->search}%");
});
})掌握 where() 闭包分组,是写出健壮、可维护 Laravel 查询的关键一步——它不只是语法技巧,更是对 SQL 执行逻辑的精准掌控。










