Laravel 的 whereLike 实际是 where('col', 'like', '%val%'),需防SQL注入、多字段用 orWhere 闭包、中文搜索需注意排序规则、无原生相关性排序、paginate 必须放最后、LIKE 无法解决分词与模糊匹配,专业搜索需 Elasticsearch 等方案。

用 whereLike 做基础模糊搜索,但别直接拼 SQL
Laravel 的 whereLike(实际是 where('column', 'like', '%value%'))能快速实现模糊匹配,但它不是独立函数,得靠 where 配合通配符。常见错误是手写 LIKE 语句时漏掉引号或转义用户输入,导致 SQL 注入或空结果。
正确做法是让 Eloquent 自动处理参数绑定:
- 用
where('title', 'like', '%' . $request->input('q') . '%'),不要拼"%{$q}%"进字符串 - 如果搜索多个字段(比如 title 和 content),用
orWhere+ 闭包包裹,避免逻辑优先级错乱 - 中文搜索注意 MySQL 默认排序规则(如
utf8mb4_unicode_ci)对大小写和重音不敏感,但不会自动处理简繁体或拼音
排序必须显式声明,orderBy 不会默认按相关性排
Laravel 不提供“搜索相关性排序”原生支持。你写 orderBy('created_at', 'desc'),它就真按时间排,跟关键词是否命中、出现次数、位置前后完全无关。
真实场景中,用户期望“标题含关键词的排前面”,这得靠数据库能力或应用层补足:
- MySQL 可用
ORDER BY (CASE WHEN title LIKE ? THEN 1 ELSE 0 END) DESC做简单分级,但性能差、难维护 - 更靠谱的是加一个计算字段:用
selectRaw('MATCH(title, content) AGAINST(?) as relevance', [$q])+ 全文索引,但要求引擎是 InnoDB、字段建了FULLTEXT索引 - 别在搜索时用
orderByRaw('LENGTH(title)')这类伪相关逻辑——它和用户意图无关,纯属误导
paginate() 要放在查询链最后,否则分页数不准
很多人把 paginate(15) 写在 where 前面,或者插在 selectRaw 中间,结果总数算错、当前页数据错乱、跳页异常。
本质原因是 paginate() 会先执行一次 COUNT(*) 查询,它必须看到完整的 WHERE 条件才能统计有效记录数:
- 正确顺序:
Model::where(...)->where(...)->orderBy(...)->paginate(15) - 如果用了
selectRaw或withCount,确保它们不影响主表过滤逻辑;否则 COUNT 可能漏条件 - 大数据量下,
paginate的 COUNT 成为瓶颈,可考虑用游标分页(cursorPaginate),但需有唯一有序字段(如id)
中文分词和模糊边界问题,LIKE 根本解决不了
用户搜“苹果手机”,where('title', 'like', '%苹果手机%') 只能匹配连续出现的字串,搜“苹果”或“手机”单独出现时就失效;更别说“iPhone”“iphon”“iphone15”这类变体。
这不是 Laravel 的锅,而是 LIKE 本身能力局限:
-
%苹%果%会误匹配“苹果梨”“苹+果酱”,且性能极差(索引失效) - 想支持错别字、拼音、同义词,必须上专业方案:Elasticsearch、Meilisearch 或 Algolia
- 哪怕只加个简单 typo 容忍,也得用 MySQL 8.0+ 的
REGEXP或 NGRAM 分词器,Laravel 层只是调用者,配置和优化都在 DB 侧
别指望改几个 where 参数就能让搜索“聪明起来”。真正要支撑业务搜索,底层数据结构和检索策略得重新设计。










