mysql无jsonb类型,误写会导致字段被降级为longtext,丧失json校验、函数支持与索引能力;gorm映射失效,json_extract等操作全部不可用。

MySQL 没有 JSONB 类型,只有 JSON;JSONB 是 PostgreSQL 的专属类型。你在 MySQL 里用 JSON 字段,就别写 JSONB —— 否则建表会直接报错或被静默转成 LONGTEXT,后续所有 GORM 映射都会失效。
MySQL 中误写 JSONB 会导致什么
MySQL 8.0 及以前版本不识别 JSONB 关键字。如果你在建表语句或迁移中写了 jsonb:
- MySQL 会把它当作未知类型,降级为
LONGTEXT(不报错但失去 JSON 校验、索引、函数能力) - GORM 自动迁移时若字段标签写
type:jsonb,同样会被忽略,实际建出的不是 JSON 字段 - 查询时看似能读,但
JSON_EXTRACT、->运算符全部失效,WHERE条件无法下推 - 更隐蔽的问题:GORM 的
datatypes.JSON或自定义Scan/Value接口,在底层收到的是[]byte,但数据库返回的其实是普通文本,导致反序列化失败或 panic
正确读取 MySQL JSON 字段的三种方式(按推荐顺序)
前提是你的表字段确实是 JSON 类型(建表语句含 milestones JSON),且 GORM v2+:
- 用
datatypes.JSON:最省心,自动处理NULL和序列化,适合结构不固定或只做整体存取的场景import "gorm.io/datatypes"Milestones datatypes.JSON `gorm:"column:milestones"` - 用
string+ 手动json.Marshal/Unmarshal:兼容性最强,但每次读写都要显式转换,容易漏判nil或空字符串 - 自定义类型实现
driver.Valuer和sql.Scanner:最可控,可加日志、缓存、预校验,适合金融/订单等强一致性场景,但必须确保Scan中对nil和[]byte类型做严格判断
MySQL 虚拟列(Generated Column)配合 JSON 字段怎么查
MySQL 支持从 JSON 字段生成虚拟列(如 name VARCHAR(100) GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(milestones, '$[0].work'))) STORED),但 GORM 默认不感知这类列 —— 它不会出现在 AutoMigrate 生成的 struct tag 里,也不会自动映射到结构体字段。
- 手动在 model struct 中添加字段,并打上
gorm:"-:all"标签(禁止写入/迁移),仅用于读取:Name string `gorm:"-:all"` - 查询时必须用
SELECT显式列出虚拟列名,GORM 的Find默认只选 struct 中带gormtag 的字段,会跳过虚拟列 - 不能用
Where("name = ?", xxx)直接查虚拟列(GORM 不知道它存在),得写原生 SQL 或用Session(&gorm.Session{DryRun: true})看生成语句再调整 - 虚拟列上的索引是有效的,但 GORM 不会帮你建;如果要用,得在
AutoMigrate后单独执行db.Exec("CREATE INDEX ...")
真正容易被忽略的点是:MySQL 的 JSON 字段内容在底层以二进制格式存储,但 GORM 驱动(如 go-sql-driver/mysql)默认返回的是 []byte,不是 string。如果你的 Scan 实现里没处理 nil 或类型断言失败,运行时 panic 就在所难免 —— 而这个错误往往只在某条数据的 JSON 为 NULL 时才暴露。











