维护 mysql 老代码的 json 的坑

🎯 标题: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'))

✏️ 总结

  1. 类型断言需严格匹配,让分支逻辑可靠触发
  2. JSON_CONTAINS candidate 必须是 JSON 文本(加引号或通过 JSON_ARRAY);
  3. MySQL 5.7 下只能拼 OR 筛选,8.0 可升级使用 JSON_OVERLAPS
  4. 可选:对 countries 同理处理、统一多个字段逻辑,代码简洁、性能更好
相关推荐
hard_coding_wang7 分钟前
使用layui的前端框架过程中,无法加载css和js怎么办?
javascript·前端框架·layui
香蕉可乐荷包蛋16 分钟前
vue3中ref和reactive的使用、优化
前端·javascript·vue.js
勤奋的知更鸟23 分钟前
JavaScript 性能优化实战:深入性能瓶颈,精炼优化技巧与最佳实践
开发语言·javascript·性能优化
白仑色1 小时前
Spring Boot + Thymeleaf + RESTful API 前后端整合完整示例
spring boot·后端·restful·thymeleaf·restfulapi
遂心_2 小时前
用React Hooks + Stylus打造文艺范的Todo应用
前端·javascript·react.js
小赖同学2 小时前
CAMEL 框架之 RolePlaying 角色扮演
人工智能·后端·aigc
F2E_Zhangmo2 小时前
第一章 uniapp实现兼容多端的树状族谱关系图,创建可缩放移动区域
前端·javascript·uni-app
写字楼里看日出2 小时前
Electron入门教程:零基础手把手教你将网页打包成桌面应用
前端·javascript
无限大62 小时前
力扣每日一题--2025.7.15
后端
JohnYan2 小时前
Bun技术评估 - 16 Debug
javascript·后端·debug