mysql升级后json字段报错,主因是字段未真正转为json类型或含非法字符;需用show create table确认类型,以json_valid()筛查并修复无效数据,注意路径大小写、转义及连接字符集。

升级后 JSON 字段报错 ERROR 1064 或查不到数据
MySQL 升级到 5.7+ 后仍报错,大概率不是版本问题,而是字段定义没真正生效。MySQL 不会自动把旧的 TEXT 或 VARCHAR 列“变成”JSON 类型——它只认建表或 ALTER TABLE 时明确声明的类型。
检查方式很简单:
- 运行
SHOW CREATE TABLE your_table;,确认字段类型确实是JSON,而不是TEXT - 如果显示的是
TEXT,哪怕你之前执行过MODIFY COLUMN info JSON,也要再跑一遍:ALTER TABLE your_table MODIFY COLUMN info JSON; - 注意:该语句会重建表,大表需评估锁表时间;若失败,常见原因是字段含非法 JSON 字符(见下一条)
JSON_VALID() 返回 0,但数据看起来是合法 JSON
升级后首次查询就失败,往往因为源数据在低版本中以 TEXT 存储时混入了不可见控制字符(如 U+0000、换行符、未转义双引号),而 JSON 类型校验比字符串严格得多。
快速定位和清理:
- 找出所有疑似无效记录:
SELECT id, info FROM your_table WHERE JSON_VALID(info) = 0 AND info IS NOT NULL; - 对单条记录人工检查:复制
info值到在线 JSON 校验器(如 jsonlint.com),看是否报错 - 批量修复建议用
JSON_REPLACE或JSON_SET替换非法字段,不要直接UPDATE ... SET info = REPLACE(info, ' ', '\n')—— 这类字符串替换可能破坏结构 - 更稳妥的做法:导出为 CSV,用 Python 脚本逐行
json.loads()+json.dumps()标准化后再导入
JSON_EXTRACT 查不到值,但 SELECT info 能看到原始内容
这是最常被忽略的兼容性细节:MySQL 5.7.8+ 对 JSON 路径表达式做了增强,但默认行为仍可能因 SQL mode 或客户端设置不同而偏差。
典型表现是:JSON_EXTRACT(info, '$.name') 返回 NULL,但 SELECT info 明明显示 {"name": "Alice"}。
优先排查这几项:
- 确认字段值不含 BOM(UTF-8 BOM 头 ),它会让
JSON_VALID()返回 1,但路径匹配失败 - 路径中键名区分大小写,且不能带空格或特殊符号——
'$.user name'必须写成'$.`user name`' - 嵌套数组访问要写全:想取
{"hobbies": ["reading", "gaming"]}的第一个爱好,得用'$.hobbies[0]',而非'$.hobbies.0' - 避免用
JSON_EXTRACT直接做WHERE条件比较,改用JSON_UNQUOTE(JSON_EXTRACT(...))或->>操作符(MySQL 5.7.13+)
应用层读取 JSON 字段时返回空字符串或乱码
这通常和连接层字符集不一致有关。即使表、列、服务器都设为 utf8mb4,客户端连接仍可能走默认 latin1,导致 JSON 中的中文被错误解码。
验证与修复步骤:
- 连接时显式指定字符集:
mysql -u user -p --default-character-set=utf8mb4 - 程序中设置连接参数,例如 Python MySQLdb:
charset='utf8mb4',PHP PDO:charset=utf8mb4 - 检查当前连接字符集:
SELECT @@character_set_client, @@collation_connection;,两个值都应为utf8mb4_* - 如果用 ORM(如 Django、SQLAlchemy),确认其配置里没有覆盖连接字符集,或强制在 URL 中加
?charset=utf8mb4
真正麻烦的从来不是升级动作本身,而是那些“看起来没问题”的历史数据——它们在 TEXT 时代被容忍,在 JSON 时代立刻暴露。别跳过 JSON_VALID() 扫描,也别信“导出再导入”能自动修复结构问题。











