PostgreSQL用ILIKE,MySQL/SQLite用LIKE;GORM不自动加%需手动拼接;建议用Scope封装并预处理关键词,中文搜索需统一字符格式。

模糊查询用 LIKE 还是 ILIKE?看数据库类型
PostgreSQL 默认区分大小写,LIKE 不会匹配大小写不一致的字段,这时候得用 ILIKE;MySQL 的 LIKE 本身就不区分大小写(取决于字段 collation),强行用 ILIKE 会报错 ERROR: operator does not exist: text ~~* text。SQLite 用 LIKE,且默认不区分大小写。
实操建议:
- PostgreSQL:优先用
ILIKE,例如db.Where("name ILIKE ?", "%"+keyword+"%").Find(&users) - MySQL/SQLite:用
LIKE即可,db.Where("name LIKE ?", "%"+keyword+"%").Find(&users) - 不想手动拼
%?GORM 提供了strings.Contains等高级方法,但底层仍转为LIKE,且不支持跨数据库统一行为,慎用于生产环境条件拼接
Where 传参时百分号 % 必须手拼,不能靠 GORM 自动加
GORM 不会自动给字符串加通配符,db.Where("name LIKE ?", "jack") 等价于精确匹配 "jack",不是模糊查 "%jack%"。漏拼 % 是最常见导致“查不到数据”的原因。
实操建议:
- 前端传来的关键词要提前清理空格:
strings.TrimSpace(keyword),避免" jack "导致"% jack %"匹配失败 - 想查“以 keyword 开头”,用
"%" + keyword;查“结尾”,用keyword + "%";查“包含”,才用"%" + keyword + "%" - 如果 keyword 来自不可信输入(如 URL query),注意 SQL 注入风险——但 GORM 的问号占位符已做参数化处理,只要不用
db.Where("name LIKE '%" + keyword + "%')这种字符串拼接,就安全
用 Scope 封装常用模糊查询逻辑,避免重复写 %
多个接口都要按 name/email 模糊查用户,每次都手拼 "%" + x + "%" 容易出错或遗漏 trim。用 Scope 可复用且语义清晰。
示例:
func SearchByName(name string) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
if name != "" {
name = strings.TrimSpace(name)
return db.Where("name ILIKE ?", "%"+name+"%")
}
return db
}
}
<p>// 使用
db.Scopes(SearchByName(keyword)).Find(&users)
注意点:
- PostgreSQL 用户记得把
LIKE换成ILIKE,否则大小写敏感可能漏结果 - Scope 内不要调用
Find或Exec,只做条件组装;否则无法链式调用其他条件 - 如果同时要查 name 和 email,别写成两个独立 Scope 并列调用——GORM 会生成
AND,而你可能需要OR,这时得用db.Where("name ILIKE ? OR email ILIKE ?", pat, pat)
中文模糊搜索遇到全角/半角、空格、标点怎么办?
GORM 层不处理字符标准化,LIKE 是字节级匹配。用户搜“ABC”(全角英文字母)查不到 “ABC”(半角),搜“hello world”中间有两个空格也匹配不上 “hello world”(一个空格)。
解决方向不在 GORM,而在数据层或应用层:
- 入库前统一转半角、去多余空格(如用
golang.org/x/text/width处理全角字符) - 建表时对关键字段加生成列(generated column)+ 索引,例如 PostgreSQL:
ALTER TABLE users ADD COLUMN name_search TEXT GENERATED ALWAYS AS (lower(translate(name, ' ,。!', ' ,.!' ))) STORED,然后模糊查这个新列 - 更重的场景考虑集成 pg_trgm 或 Elasticsearch,GORM 只负责发查询,不承担文本分析职责
模糊查询真正难的从来不是写那行 Where,而是你查的“模糊”到底指什么——是字符层面的通配,还是语义层面的近似。后者 GORM 帮不上忙。


















