Laravel执行LIKE模糊查询时如何忽略数据库字段的特殊字符
Laravel搜索特殊字符匹配问题解决方案
现有查询逻辑是直接对原存储字段做LIKE匹配,当存储内容带'等特殊字符,而用户搜索关键词省略特殊字符时,字符串无法匹配,自然返回不到对应结果。
可选实现思路
方案1:查询时动态移除字段特殊字符
可在SQL查询层面对字段值做特殊字符清洗后再匹配,以MySQL为例,可借助REGEXP_REPLACE函数实现,Laravel中写法如下:
$products = Product::where(function($query) use ($searchTerm) { // 清洗product_name后匹配 $query->whereRaw("REGEXP_REPLACE(product_name, '[^A-Za-z0-9 ]', '') LIKE ?", ["%{$searchTerm}%"]); $query->orWhere('product_category', 'LIKE', "%$searchTerm%"); $query->orWhere('product_description', 'LIKE', "%$searchTerm%"); }) ->where('lang', '=', 'en') ->orderBy('product_name', 'ASC') ->get();
该方案缺点:每次查询都需要对全表对应字段做函数计算,无法命中索引,数据量较大时查询性能会明显下降,仅适合小数据量临时使用。
方案2:新增预处理搜索字段(最优方案)
提前对需要搜索的字段做特殊字符清洗,存储到独立的专用搜索字段,查询时直接匹配预处理字段,性能和匹配准确率都有保障,实现步骤如下:
- 给
products表新增product_name_search字段,类型和长度与product_name保持一致即可 - 在Product模型中绑定保存事件,新增/更新商品时自动生成清洗后的搜索字段值:
// app/Models/Product.php protected static function booted() { static::saving(function (Product $product) { // 移除所有非字母、数字、空格的特殊字符 $product->product_name_search = preg_replace("/[^A-Za-z0-9 ]/", '', $product->product_name); // 若需要支持分类、描述的特殊字符匹配,可同理新增对应search字段同步处理 }); }
- 执行一次批量更新,给历史已有商品的
product_name_search字段补全值 - 修改查询逻辑,将商品名匹配逻辑改为对预处理字段的查询:
$products = Product::where(function($query) use ($searchTerm) { // 直接匹配预处理后的搜索字段 $query->where('product_name_search', 'LIKE', "%{$searchTerm}%"); $query->orWhere('product_category', 'LIKE', "%$searchTerm%"); $query->orWhere('product_description', 'LIKE', "%$searchTerm%"); }) ->where('lang', '=', 'en') ->orderBy('product_name', 'ASC') ->get();
该方案优势:查询时无额外计算开销,可给product_name_search字段加索引进一步提升查询性能,可稳定覆盖所有特殊字符省略的搜索场景。
扩展说明
如果业务有全字段模糊搜索、分词搜索等更复杂的搜索需求,可考虑使用Laravel Scout对接Meilisearch、Elasticsearch等全文检索引擎实现,性能和搜索效果会更好,但开发和维护成本相对更高。
内容的提问来源于stack exchange,提问作者fufubrocat
相关产品推荐
相关产品推荐

