MySQL不支持直接导入JSON文件,需用Python流式解析后批量插入或mysqlsh的util.importJson(仅限NDJSON格式)。
MySQL 5.7+ 直接读取 JSON 文件的限制
mysql 本身不支持像 load data infile 那样直接把一个 json 文件“一键导入”到表里——它没有内置的 json 批量解析 + 插入语法。你看到的 json_table() 或 json_extract() 都是针对单行 json 字符串的,不是文件级操作。
所以实际路径只有两条:要么用客户端工具预处理 JSON 成 SQL(INSERT 语句),要么用编程语言中转解析后批量写入。
- MySQL 8.0+ 的
JSON_TABLE()只能处理字符串字面量或列值,不能读磁盘文件 -
LOAD DATA INFILE只认 CSV/TSV 等分隔格式,对 JSON 报错:ERROR 1109 (42S02): Unknown table 'json' - 即使把 JSON 数组每行存成一行字符串,也得先用
JSON_VALID()过滤脏数据,否则INSERT会因类型不匹配静默失败或报错
Python + pymysql 批量插入 JSON 数组(推荐方案)
这是最可控、调试最方便的方式。核心是:用 Python 解析 JSON 文件 → 映射字段 → 构造参数化 INSERT → 批量执行。
假设 JSON 文件 data.json 是一个对象数组,每个对象字段与 MySQL 表 users 的列名一致:
[
{"id": 1, "name": "Alice", "score": 95.5},
{"id": 2, "name": "Bob", "score": 87.0}
]
- 别用
json.load(f)一次性全读进内存——大文件(>100MB)容易 OOM;改用ijson流式解析,或分块读取 - 字段名必须严格对应表结构;如果 JSON 有嵌套(如
{"user": {"name": "A"}}),必须提前用d.get("user", {}).get("name")展平 - 插入前检查 NULL 和类型:MySQL 的
INT列不能插"null"字符串,得转成None;浮点字段避免传字符串"95.5"(虽能隐式转换,但易出精度问题) - 用
executemany()而非循环execute(),1000 条记录性能差 10 倍以上
用 mysqlsh 的 JSON 导入(MySQL 8.0.22+)
如果你用的是较新版本 MySQL,mysqlsh(MySQL Shell)提供了 util.importJson(),是目前最接近“原生导入”的方案。
它要求 JSON 文件是**换行分隔的 JSON 对象(NDJSON)**,不是数组包裹的格式:
{"id": 1, "name": "Alice"}
{"id": 2, "name": "Bob"}
- 命令示例:
util.importJson("/path/to/data.json", {schema: "test", table: "users", dialect: "json"}) - 自动跳过非法 JSON 行,但不会告诉你哪一行错了——建议先用
jq -n '1' data.json | head -n 10验证前几行格式 - 不支持字段重命名或类型转换;JSON 键名必须和表列名完全一致(大小写敏感)
- 导入过程无法加事务控制,失败时已写入的数据不会回滚
常见映射陷阱:时间、布尔、嵌套字段
JSON 里的时间字符串("2023-10-05T14:30:00Z")、布尔值(true)、深层嵌套对象,最容易在导入时被忽略或错转。
- MySQL 的
DATETIME不接受 ISO 8601 带时区格式,需用 Python 的datetime.fromisoformat().replace(tzinfo=None)剥离 TZ,或用 MySQL 的STR_TO_DATE()在 SQL 侧转换 - JSON 的
true/false会被 Pythonjson模块转成True/False,但 MySQL 的TINYINT(1)接收没问题;若目标列是ENUM('yes','no'),就得手动映射{True: 'yes', False: 'no'} - 遇到
{"meta": {"tags": ["a","b"], "version": 2}}这种结构,别硬塞进单个TEXT列——该拆表就拆表,否则后续查tags就只能靠JSON_CONTAINS(),没法走索引
真正麻烦的从来不是“怎么导入”,而是“JSON 结构是否真的适配关系模型”。字段含义模糊、动态 key、混合类型数组(比如 "scores": [95, "N/A", 87])——这些得在解析层做清洗,数据库层救不了。











