后端-数据库-MySQL JSON列自动重排字段顺序
问题现象
- 在 Schema 模块编辑取值 JSON 时,按自定义顺序输入的 JSON 字段(如
My_Field → Type → Local_Variables → Default_Fallback → Routing_Rules),保存后重新打开编辑,JSON 字段变为字母序排列 - 已验证输入时顺序正确(前端 Pydantic 解析为有序 dict),但数据库中读取回来顺序就变了
核心问题
根因:MySQL 原生 JSON 列在处理 JSON 对象时会自动按字母序重排键名,无法保留插入顺序。
数据链路分析:
前端输入 → json.loads() (Python 3.7+ dict 保序 ✓)
→ SQLAlchemy JSON 列 → MySQL JSON 列 (MySQL 内部解析后字母序重排 ✗)
→ 写回时用 json.dumps() 输出 → 前端 (顺序已变 ✗)
关键对比值: | 阶段 | 顺序状态 | |------|---------| | 前端输入 Pydantic 解析后 | 保序 ✓ | | MySQL JSON 列写入后 | 字母序 ✗ | | MySQL JSON 列读回后 | 字母序 ✗ | | 改用 TEXT 列后 | 保序 ✓ |
解决方法
采用双保险方案:后端 TEXT 列保序(主)+ 前端规范顺序展示(辅)。
1. 后端:JSON 列 → TEXT 列
修改 src/extensions/schema/model.py:106:
# 改前
value_json: Mapped[dict | list | None] = mapped_column(JSON, nullable=True)
# 改后
value_json: Mapped[str | None] = mapped_column(Text, nullable=True)
修改 src/extensions/schema/service.py:
- create_atom / update_atom:存储原始文本,仅用 _parse_value_json 做格式校验
- _serialize_atom:直接返回文本(不经过 json.dumps 再序列化)
数据库迁移(Alembic):
ALTER TABLE schema_atoms MODIFY COLUMN value_json TEXT
生成迁移文件并执行:
alembic revision --autogenerate -m "change value_json to TEXT"
alembic upgrade head
2. 前端:规范顺序展示(安全网)
提取工具函数到 web/admin/src/views/modules/schema/value-json-order.ts:
- 常量 VALUE_JSON_FIELD_ORDER 定义规范顺序
- 函数 reorderJsonFields() 按规范顺序重排后展示
下次防错措施
快速定位:对比 SQLAlchemy 模型字段类型与 MySQL 表结构是否一致
SHOW CREATE TABLE schema_atoms;
value_json 显示 json 而非 text,说明迁移未执行或被回退。
流程改进:
- 新模块设计时,如有"保序"要求的键值数据,直接使用 Text 列存储,避免 JSON 列
- 数据库迁移后,写自动化测试验证字段顺序(本案例已有 TestCreateAtomRoundTrip 集成测试)
验证脚本(后端测试已有):
pytest tests/test_schema_value_json.py -v