当前位置: 首页 > news >正文

第五难:MongoDB到PostgreSQL的类型转换

问题

MongoDB和PostgreSQL的数据类型完全不兼容:

MongoDBPostgreSQL问题
ObjectId无对应类型主键转换
BSON对象JSONB嵌套结构
数组Array类型声明

解决方案

在配置表的扩展字段定义类型映射:

{ "mongoCollection": "user_profile", "pgTable": "user_profile", "fieldMapping": { "_id": "id", "preferences": "preferences", "tags": "tags" }, "typeMapping": { "_id": "OBJECTID_TO_VARCHAR", "preferences": "JSONB", "tags": "INTEGER_ARRAY" } }

类型转换代码:

private String convertValue(Object value, String typeRule) { if (value == null) return "NULL"; switch (typeRule) { case "JSONB": // {name: "test"} → '{"name":"test"}'::jsonb String json = toJsonString(value); return "'" + escapeSql(json) + "'::jsonb"; case "INTEGER_ARRAY": // [1,2,3] → ARRAY[1,2,3]::INTEGER[] List<Integer> list = (List) value; return "ARRAY[" + String.join(",", list) + "]::INTEGER[]"; case "OBJECTID_TO_VARCHAR": // ObjectId("507f...") → '507f...' return "'" + value.toString() + "'"; default: return convertDefault(value); } }

复盘:一个月完成迁移的关键

整体架构:塔外-塔内双链路

┌──────────── 塔外系统 (Outer) ────────────┐
│ │
│ ① API触发同步 │
│ ② 查询配置表 → 拆分公司级/店铺级配置 │
│ ③ 构建MQ消息 → 投递RocketMQ │
│ ④ MQ Consumer │
│ ├─ SHOW CREATE TABLE 获取表结构 │
│ ├─ 流式读取源数据库 │
│ ├─ 生成 DELETE + INSERT SQL │
│ ├─ 分号替换为特殊符号 │
│ └─ 上传到 OSS │
└───────────────────────────────────────────┘

│ OSS中转

┌──────────── 塔内系统 (Inner) ────────────┐
│ │
│ ⑤ 定时任务 / 手动触发 │
│ ⑥ 扫描OSS目录 → 获取待处理SQL文件列表 │
│ ⑦ 流式下载SQL文件 → 逐行读取 │
│ ├─ 特殊符号还原为分号 │
│ ├─ 批量执行(1000条/批) │
│ └─ setAutoCommit(true) 防止事务过大 │
│ ⑧ 执行成功 → 立即删除OSS文件 │
└───────────────────────────────────────────┘

核心亮点总结

技术点传统方案本方案效果
表结构获取手写100个MapperSHOW CREATE TABLE动态解析零硬编码,支持任意表
SQL分隔符;判断结束特殊符号;#END#支持数据含分号、换行符
同步策略全量同步or硬编码配置表+占位符灵活配置,4种策略
大数据量处理一次性加载(OOM)流式读取+临时文件常量级内存,50W+行稳定
扩展性新增表需改代码只需加配置秒级上线新表同步

做对的3件事

1. 从工具中偷师学艺
Navicat的导入/导出功能启发了整体方案,SHOW CREATE TABLE是突破口

2. 把复杂逻辑放在塔外
塔内只负责执行SQL,逻辑简单;塔外可以随意调试、优化

3. 配置驱动,而非代码驱动
新增表只需加配置,不改代码。后续维护成本趋近于0

最终效果

指标数据
迁移表数量200+张(含后续新增)
最大单表数据1000+万行
首次全量同步10-30分钟
日常增量同步公司级表约30秒,店铺级表约1分钟
内存占用稳定在200MB左右
OOM次数0(连续运行3个月)
工期25天(提前5天完成)


写在最后

以上便是我这次迁移实战的全部分享。绝非标准答案,但希望能为你带来一丝灵感。

这次迁移让我深刻体会到:
好的架构不是设计出来的,而是从实际问题中"偷"出来的。

当你面对技术难题时,不妨问自己:

  • 有没有现成的工具已经解决了类似问题?不要重复造轮子!!(Navicat)
  • 数据库/框架本身提供了什么能力?(SHOW CREATE TABLE、setFetchSize)
  • 能否用配置代替硬编码?(配置表+占位符)

感谢那些"默默扛下所有"的技术细节

  • SHOW CREATE TABLE—— 你扛下了表结构解析的苦活
  • stmt.setFetchSize(Integer.MIN_VALUE)—— 你默默守护了内存安全
  • ;#END#—— 你可能是全网最诡异但最实用的分隔符
  • RocketMQ的TAG过滤—— 你让消息路由变得优雅
  • CompletableFuture—— 你让塔内并发处理成为可能
  • System.lineSeparator()—— 你让SQL文件格式清晰明了
http://www.gsyq.cn/news/1613054.html

相关文章:

  • 3步解锁百度网盘30倍下载速度:从限速到飞驰的实战指南
  • 别再傻傻分不清!一文搞懂Chiplet、SiP、SoC和MCM到底有啥区别(附AMD实例)
  • SENAITE LIMS:现代化实验室信息管理系统的架构解析与实施指南
  • 别再死记硬背公式了!用Python可视化理解拉梅系数与正交坐标系
  • 112G AI 服务器高速线束自动化生产线定制指南 非标线束整线方案参考
  • 别再混淆了!嵌入式开发中的TCM、ITCM、DTCM到底怎么用?(以Cortex-M为例)
  • 别再直接积分了!用MPU6050陀螺仪数据算姿态角,为什么你的无人机飞机会‘乱飘’?
  • AI合规高阶:AI跨境合规的难点与解决方案
  • 别再死记硬背公式了!用Python可视化理解拉梅系数在柱坐标/球坐标下的应用
  • 审稿人视角:你的稳健性检验真的“稳健”吗?避开这5个常见误区
  • 别只看容量!选电容时,ESR和自谐振频率才是高频电路成败的关键
  • 小升初家长信息管理系统:从碎片到结构化的知识管理方案
  • 从ICPC交互题到算法面试:手把手教你用二分+单调性优化解决矩阵第K大问题
  • 别再傻傻分不清了!5分钟搞懂NPN和PNP三极管在传感器接线中的实战区别
  • OpenCV实战:用matchGMS()函数5分钟搞定SIFT/ORB特征匹配的误匹配剔除
  • Linux 3.0 HDMI驱动机制详解
  • 从“能用”到“好用”再到“智能”:2026年电子合同行业五大趋势解读
  • 从谱松弛到双随机:图解Graph Matching三大优化算法,附NumPy实现与性能对比
  • 新手避坑指南:从ENA下载数据到QIIME2 2023.5版完成16S扩增子分析全流程
  • 2026 年线下销售数字化,智能工牌远不止是个录音设备
  • 2026 国内优质 GEO(生成式 AI 引擎优化)服务商推荐|企跃龙门领衔全梯队机构选型指南
  • 别再只做差异分析了!用R包AUCell给你的单细胞数据做个‘基因集富集体检’
  • 终极日志分析神器glogg:让海量日志处理变得简单高效的完整指南
  • Cadence 17.4 原理图库管理实战:从自带库解析到自定义元件创建(附避坑清单)
  • Playwright for Java自动化测试框架性能优化全链路实践
  • 解决VSCode里ctrl+鼠标点击无法跳转python源码的问题
  • 工厂储气罐积水严重如何快速处理不影响生产
  • 2026粉笔公考冲刺高分能力客观评测
  • yii2 migrate 时直接执行 SQL语句
  • 别再只懂RGB了!用Python+OpenCV实战HSV色彩空间,轻松搞定图像分割与目标提取