MySQL原生支持用mysqldump --tab将结构(.sql)和数据(.txt)分导至服务端本地目录,需FILE权限;跨库表导JSON须先分结构与数据再转换,避免类型丢失、NULL及时间格式问题。
用 mysqldump + --tab 导出结构和数据到不同目录
mysql 原生支持把表结构(.sql)和数据(.txt)分开导出,但默认不生成 json。想跨库跨表做结构与数据分离,得先用 mysqldump 拆出原始文件,再转 json —— 这是最稳的起点。
关键不是“一步导 JSON”,而是“先分再转”,否则字段类型丢失、NULL 处理错、时间格式乱。
-
mysqldump --no-data --databases db1 db2 > schema.sql:只导结构,含CREATE DATABASE和CREATE TABLE -
mysqldump --tab=/tmp/ --fields-terminated-by='\t' --lines-terminated-by='\n' db1 table_a table_b:每个表生成table_a.sql(建表语句)和table_a.txt(纯数据,制表符分隔) - 注意:
--tab要求 MySQL 有FILE权限,且目标路径必须是服务端本地路径,不是你本地机器
用 SELECT ... INTO OUTFILE 配合 JSON_OBJECT 直接吐 JSON 行
如果只要数据(不要建表语句),且 MySQL ≥ 5.7,JSON_OBJECT 是最轻量的方案。它能按字段名动态拼 JSON 对象,避免手写字符串拼接出错。
但别直接 SELECT JSON_OBJECT('id', id, 'name', name) FROM t 全表查——大表会 OOM。得加条件或分页。
-
SELECT CONCAT('[', GROUP_CONCAT(JSON_OBJECT('id', id, 'title', title) SEPARATOR ','), ']') FROM posts WHERE status = 1 LIMIT 1000:拼成数组,适合小结果集 - 更安全的做法是用游标或应用层分批:每次查 500 行,每行
JSON_OBJECT,输出一行一个 JSON 对象(NDJSON 格式) - 注意:
JSON_OBJECT会把NULL转成null,但空字符串''还是"";时间字段如created_at默认转为"2024-03-15T08:22:33.000Z"格式(取决于时区设置)
跨库 JOIN 导出 JSON 时字段名冲突怎么破
比如 SELECT JSON_OBJECT('id', a.id, 'id', b.id) 会报错:JSON_OBJECT 不允许重复键名。跨库表关联时,同名字段(如都叫 id、name)必须显式重命名。
不能靠应用层后期改 key,因为导出阶段就要定型。结构一旦写死,下游解析就难改。
- 用
AS显式别名:SELECT JSON_OBJECT('user_id', u.id, 'order_id', o.id, 'user_name', u.name) FROM db1.users u JOIN db2.orders o ON u.id = o.user_id - 别偷懒写
u.*或o.*——JSON_OBJECT不支持通配符,会语法错误 - 如果字段太多,建议先
DESCRIBE db1.users查列名,再用脚本生成带别名的JSON_OBJECT表达式,避免漏列或拼错大小写
Python 脚本合并多库表结构 + 数据转 JSON 的最小可行链路
纯 SQL 很难搞定“跨库结构合并 + 类型映射 + 数据 JSON 化”,最终大概率要写脚本。重点不是写多漂亮,而是控制三件事:字段类型推断、NULL 处理一致性、输出流式防内存炸。
用 mysql-connector-python 比 PyMySQL 更稳,它原生支持 cursor.column_names 和 cursor.description,能拿到真实字段类型(比如 DECIMAL(10,2) 而不只是 float)。
- 结构提取:遍历
SHOW CREATE TABLE db1.t1,正则提取字段定义,存为 Python dict,key 是字段名,value 含 type、nullable、default - 数据导出:用
cursor.execute("SELECT * FROM db1.t1 LIMIT 10000"),逐行用json.dumps(row, default=str)——default=str是为了兜住 datetime、Decimal 等非 JSON 原生类型 - 陷阱:
fetchall()会把全部结果加载进内存,10 万行 Decimal 就可能吃掉 1GB;必须用fetchmany(1000)分块处理
结构和数据分离不是为了好看,是让后续 JSON Schema 校验、字段变更比对、增量 diff 成为可能。但所有方案都绕不开一个点:MySQL 的 TEXT 字段里藏了换行和双引号,直接塞进 JSON 会破坏结构 —— 导出前务必用 REPLACE(col, '\n', '\n') 和 REPLACE(col, '"', '\"') 预处理,这个细节九成脚本会漏。

















