🎯 标题:Go + MySQL 5.7 中 JSON 多选过滤实战与常见坑
1. 类型断言失配导致条件不生效
你在 filter["platforms"]
中存的是 []string{"6"}
,而代码中做的是 []int
断言:
go
if platformStrs, ok := filter["platforms"].([]string); ok { ... }
原先使用 []int
断言会失败,导致该分支被跳过。不匹配类型的断言会让你的筛选逻辑完全不执行。
✅ 解决方案:
- 明确统一
platforms
的类型,建议统一使用[]string
或[]int
; - 或同时支持两种类型的断言处理,避免失配 silent fail。
2. JSON_CONTAINS 传参格式错误
你的 SQL 拼接片段类似这样:
scss
JSON_CONTAINS(t.platforms, 1)
但 MySQL 的 JSON_CONTAINS(target, candidate)
要求 candidate
是 合法 JSON,整数需要用字符串格式传入:
javascript
JSON_CONTAINS(t.platforms, '1')
否则会报 "Invalid JSON text in argument 2" 错误 (MySQL, Stack Overflow)。
3. MySQL 5.7 实现多选 OR 筛选
MySQL 5.7 没有 JSON_OVERLAPS
(OR 语义)函数,因此只能用 JSON_CONTAINS
+ OR
:
go
var ors []string
for _, p := range platformStrs {
pi, _ := strconv.Atoi(p)
ors = append(ors, "JSON_CONTAINS(t.platforms, ?)")
params = append(params, fmt.Sprintf("%d", pi))
}
whereClauses = append(whereClauses, "(" + strings.Join(ors, " OR ") + ")")
传入的参数最终生成 SQL:
javascript
... WHERE (JSON_CONTAINS(t.platforms, '6') OR JSON_CONTAINS(t.platforms, '2'))
确保 candidate 是字符串、传入顺序、参数位置都正确。
4. MySQL 8.0 更优方案:JSON_OVERLAPS
若使用 MySQL ≥8.0,可以直接用更简洁高效的 JSON_OVERLAPS
:
javascript
JSON_OVERLAPS(t.platforms, '[1,2,3]')
它代表的是"任意匹配"(OR 语义),性能上也支持多值索引优化 (Stack Overflow)。
📋 完整流程回顾
问题 | 原因 | 解决方案 |
---|---|---|
类型不匹配 | filter["platforms"] 是 []string ,断言 []int 失败 |
明确类型或同时支持多种断言 |
参数格式不对 | JSON_CONTAINS(..., 1) -> 非 JSON 文本 |
用字符串包裹: '1' 或 fmt.Sprintf("%d", pi) |
多选逻辑 | MySQL 5.7 无 OR 数组匹配函数 | 拼多个 OR JSON_CONTAINS(...) |
性能问题 | 复杂 OR 和 JSON_CONTAINS 不太高效 | 升级 MySQL 8 后用 JSON_OVERLAPS |
✅ 推荐最终代码片段
go
if platformStrs, ok := filter["platforms"].([]string); ok && len(platformStrs)>0 {
var ors []string
for _, ps := range platformStrs {
pi, err := strconv.Atoi(ps); if err!=nil { continue }
ors = append(ors, "JSON_CONTAINS(t.platforms, ?)")
params = append(params, fmt.Sprintf("%d", pi))
}
whereClauses = append(whereClauses, "(" + strings.Join(ors, " OR ") + ")")
}
SQL 生成后类似:
javascript
WHERE (JSON_CONTAINS(t.platforms, '6') OR JSON_CONTAINS(t.platforms, '2'))
✏️ 总结
- 类型断言需严格匹配,让分支逻辑可靠触发;
- JSON_CONTAINS candidate 必须是 JSON 文本(加引号或通过 JSON_ARRAY);
- MySQL 5.7 下只能拼 OR 筛选,8.0 可升级使用 JSON_OVERLAPS;
- 可选:对
countries
同理处理、统一多个字段逻辑,代码简洁、性能更好。