跳转至

后端-数据库-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