迁到 MongoDB 以后 Hibernate 那套接不上,Spring Data 该管哪一段?

集合名、字段名都迁完了,Java 服务这边还想继续用 Session、懒加载、一对多级联。编译器一报,才发现那些 API 在 Mongo 这边对不上号。文档库跟关系 ORM 本来就不是同一套语义。Mongo 这边 Java 生态里更常见的入口是 Spring Data MongoDB。

文档库别硬套关系 Session

关系 ORM 围着表、外键、Session / 一级缓存、脏检查、懒加载代理转。MongoDB 存的是文档(和可选的引用),没有「按外键自动拼实体图」那一套一等公民。事务、锁、关联加载的默认假设也不一样。把 @OneToMany、Session.get、LazyInitializationException 心智原样搬过去,只会到处找不存在的 API。

《Spring Data MongoDB 参考文档》开篇就定位:用模板类做核心 API,再用轻量 Repository 风格访问,编程模型和 Spring 其它 Data 模块对齐。功能概览页列了配置与驱动连接、MongoTemplate、异常翻译、对象映射、注解元数据、生命周期事件、Query/Criteria DSL、Repository 自动实现、多文档事务、Change Streams、GridFS、地理与向量检索等——管的是「文档怎么连、怎么映、怎么查、怎么订阅读」,不是 Hibernate Session 的替身。

命名上也尽量贴 MongoDB Java 驱动,方便把已有驱动经验映射到 Spring API,而不是再学一套「Mongo 版 JPA」。

Template 和 Repository 各管什么

按功能说明的分工:

  • 大多数增删改查、按条件更新、计数之类,优先 Repository 或 MongoTemplate。两者都走同一套映射。
  • 需要贴近驱动、拿 MongoDatabase、做不太适合派生查询的操作时,用 Template 的回调往下钻。
  • 映射把文档和 POJO 对上。复杂聚合、批量更新往往直接写 Query / Aggregation,别指望 Criteria 自动生成跟 SQL 一样的 join。
  • GridFS 适合大文件。Change Streams 适合「集合有变更就推下来」。多文档事务、会话在独立章节,迁库时按需打开,别假定「开了 Spring 事务注解就和 InnoDB 行为一模一样」。

版本从 2.x 升到 3.x、4.x、5.x 时,驱动与映射的破坏性变更要看文档里的升级说明。参考站首页有 What’s New / Upgrade Notes 入口。别在生产上跳大版本却只改依赖号。

迁库时人容易卡的几处

  • 原来靠外键级联删的,到文档模型要重新想:内嵌、手工引用、还是应用层补偿。内嵌读路径简单,文档变大、并发更新同一文档会变疼。只存引用则每次拼装多一次查询。
  • 「懒加载一个关联集合」在 Mongo 里常常变成另一次查询或一次聚合,显式写出来更安全,也少在调试时猜「这次发了几条命令」。
  • 事务边界:单文档原子性是常态。跨文档事务有成本,也不是每个部署都开。能靠单文档设计收掉的一致性,就别先上多文档事务。
  • 查询直觉:没有固定 schema 不等于没有索引规划。字段名一改,旧索引和旧查询会一起哑火。派生查询方法名和字段对不上时,宁可写成显式 @Query / Criteria,少靠魔法方法名硬猜。
  • 异常类型:Spring Data 会把驱动异常翻成 Spring 的 DataAccessException 体系,上层 catch 策略要跟着改,别再只认 Hibernate 那串异常名。

这篇不给出谁更快的数字,也没有「ORM 淘汰」之类的口号。关系库继续用 Hibernate / JPA 很常见。库已经迁到 Mongo 时,Java 侧应接的是 Spring Data MongoDB 的 Template / Repository / 映射与流式能力,而不是再找一个「Mongo 版 Session」。历史上还有过面向文档库的 ORM 实验,多数项目最终还是回到官方驱动或 Spring Data 这条主线,正文不展开那些已停更的支线。

你们迁完以后,是 Repository 派生日志查询为主,还是大量 Aggregation 写在 Template 里?有没有人坚持再套一层类 Hibernate 的封装,后来又拆掉的?