写点什么

Spring Data 与 MongoDB:不协调的设计

  • 2013-11-14
  • 本文字数:2442 字

    阅读完需:约 8 分钟

MongoDB 是一款非常知名的 NoSQL 文档数据库,而 Spring 则是 Java 领域著名的开源框架。除了构成 Spring 核心的 IoC 与 AOP 之外,Spring 也有大量应用于各个不同领域的子框架,其中 Spring Data 就是专门针对数据处理的一个子项目。在 Spring Data 下有 Spring Data JPA Spring Data MongoDB Spring Data Redis 等子项目,从名字就可以看出来这些子项目所针对的目标。其中,Spring Data MongoDB 是专门针对 MongoDB 的一个子项目,旨在通过 Spring 的方式来操纵 MongoDB,那么这种集成是简化了开发还是阻碍了开发呢?

Prashant Deva Chronon 的创始人与 CTO。他是一位持续创业者,还创办了 Placid Systems、AntlrStudio 及 Virtual Ant。作为一名极客,Deva 喜欢尝试各种新鲜技术,在使用了 Spring Data MongoDB 一段时间后,他认为这个框架在设计上存在着严重的问题,并撰写了文章进行了深入且详尽的分析。

Spring 框架开发者们喜欢到处宣扬他们对 MongoDB 提供的支持,并以此作为优于其他框架的一个资本。不过,如果在真正的项目中使用 Spring Data MongoDB 的话,你就会发现框架在某些特性上的严重缺失以及设计上的巨大失误。

Spring Data MongoDB 试图将 ORM 风格的架构硬塞到非关系型数据库中,这直接造成在实际项目中根本无法使用的严重后果,下面就来谈谈这背后的原因:

无法检索字段,只能获取整个文档

这是 Spring Data MongoDB 设计上最大的瑕疵。它试图用 SQL 数据库中的行对文档进行建模,并且希望你像 ORM 一样创建“实体”类。这两者根本就不是一回事。文档可要比 SQL 数据库中的行复杂多了,也大多了。

对于 SQL 数据库中的行来说,它认为你在大多数查询中都会获取到里面的所有数据,否则数据就应该被划分到多张表中。不过文档与之完全不同,文档可以嵌套,很多时候你只想从数据库中获取到文档的一个子集而已。

但对于 Spring Data MongoDB 的“实体”模型来说,你不得不在每次查询中都检索出整个文档才行。

没有 DBRef 延迟加载

这个就更加疯狂了。如果通过 DBRefs 来引用其他文档,那么 Spring Data MongoDB 就会得到整个文档而不是文档引用。如果通过 DBRefs 连接了大量文档,那么一个只想获得几个字段的简单查询都会导致获取到整个文档图!

实际情况是这个 Bug 报告已经有将近两年时间了,被指定为“低优先级”状态,也没有什么解决方案,这太让人难以置信了,这表明 Spring Data MongoDB 的愿景与实际的使用之间存在着多么大的差距。

不支持游标

想要通过游标遍历集合吗?没门。要么就取出整个集合,要么就转而使用原生的 Mongo Java 驱动。

不完备的聚合框架支持

Spring Data MongoDB 是从不久之前才开始支持 MongoDB 聚合框架的,就像框架的其他部分一样,这种支持也是个半成品。

框架文档很少并且容易让人产生混乱,在实际项目中所需的大多数聚合查询都没法在Spring Data MongoDB 的文档中找到,你只能使用原生的驱动才行。

不完善的索引支持

虽然可以通过框架将某个字段标记为“加索引的”,但其他操作却根本就不知道这回事。

就拿MongoDB 中的一个例子来说吧,如果某个字段是唯一且稀疏的,那么你就不能使用“null”值向文档中插入一次以上。这意味着在第2 次插入时,该字段就不应该在第1 次插入的位置处出现。

然而,由于Spring 强迫你在一个类中定义文档的字段,因此最后需要将null 赋给不存在的字段。如果该字段拥有唯一的稀疏索引,那么这会导致运行期错误,因为Spring 在根据实体对象创建查询时(以注解的形式直接定义在字段上),它根本就不知道索引的存在。

Spring 还提供了一个 ensureIndex() 方法用于手工在字段上创建索引,无需使用注解,不过文档中并没有提及何时该使用这种方式、使用的频率是多少,以及调用的性能是怎样的。

无法切换数据库

很多时候,你希望将数据存储在单个 MongoDB 实例的不同数据库中,比如说要保持不同客户数据的分离。

如果使用原生的 Mongo 驱动,那么切换数据库简直就是小菜一碟,直接调用 getDb(dbName) 就行了。但如果使用 Spring Data MongoDb,那么这几乎是一件无法做到的事情,除非你愿意自己写大量的代码(不过这么做的话在新版框架发布后可能就会出现移植性问题)。

让人奇怪的日志框架

我已经就 Spring 的文档问题专门写过一篇文章。Spring 文档说它使用的是 Jakarta Commons Logging ,不过 Spring Data 显然使用的是 SLF4J。然而,Spring Data 文档却压根儿就没有提过这事。

这意味着如果开始使用 Spring Data,那么你可能就会遇到很多文档中没有提及的运行期错误,这时没别的办法,上 StackOverflow 上找答案吧。

不支持文档的动态特性

使用 MongoDB 这样的面向文档的数据库最大的原因就在于其动态特性了。比如说同一集合中的文档可以不同,这样同一个集合中就可以有多个版本的文档,然后逐渐升级,文档也可以嵌套。键名不必事先知道,这样就可以直接向文档中插入属性映射。

但事实却是 Spring Data MongoDB 丢弃了 MongoDB 的这个最基本的特性,并且试图在其上构建一个确定的、预先定义好的 ORM 风格的层,这直接造成框架与底层数据库之间的不匹配。

结论

Spring Data MongoDB 似乎是由一些压根儿就没有在真正的项目中用过 MongoDB 的人设计出来的,它试图将面向文档的数据库硬塞到 ORM 风格的框架中。

这导致了框架与数据库之间的不匹配,Spring Data MongoDB 反而成为了一个负担而不是帮助我们简化开发。最后,你还是不得不在几乎所有真正的项目开发中使用原生的 MongoDB Java 驱动。

后记

各位 InfoQ 读者,你曾经使用过 Spring Data MongoDB 进行过 MongoDB 开发么,你对于 Spring Data MongoDB 的使用感受是如何呢?是否与 Deva 的经历一致呢?我曾经在项目中尝试过 Spring Data MongoDB,使用下来的一个直观感受就是它将简单的事情搞复杂了。直接使用原生 Java 驱动来操纵 MongoDB 是个非常简单且直观的过程,而 Spring Data MongoDB 却沿用了它一直以来的处理风格,那就是 IoC,需要先进行注入,然后从容器中获取所需的对象,将原本很轻松的操作变得复杂起来,不知各位读者有什么样的感受呢,欢迎讨论。

2013-11-14 10:2411928
用户头像

发布了 88 篇内容, 共 272.0 次阅读, 收获喜欢 9 次。

关注

评论

发布
暂无评论
发现更多内容

基于Jena的知识推理

华为云开发者联盟

推理 知识推理 Jena 推理引擎 RDF图

云图说|ROMA演进史:一个ROMA与应用之间不得不说的故事

华为云开发者联盟

华为云 应用 ROMA 云图说 应用使能

灵活运用分布式锁解决数据重复插入问题

vivo互联网技术

分布式锁 服务器 并发

生产上数据库死锁,是该程序员祭天了

skow

Java MySQL 面试

爬虫入门到放弃04:爬虫=犯罪?对不起,我对钱没有兴趣

叫我阿柒啊

爬虫 robots.txt

关于线程的执行顺序,可能真的只是你以为的你以为

华为云开发者联盟

Java 线程 多线程 Thread 任务调度

爱情,婚姻,与AI

脑极体

如何包容他人的多样性

escray

学习 极客时间 朱赟的技术管理课 7月日更

《MySQL是怎样运行的》读后思考

MySQL

异常是怎么被处理的?这题的答案不在源码里面。

why技术

面试 JVM 字节码

星云矿工fil分币系统软件开发

获客I3O6O643Z97

fil币 星际联盟fil矿机靠谱吗

当女性撰写科技新闻,她在报道什么?

脑极体

《全国移动App第二季度安全研究报告》

InfoQ_11eaedef67e9

网络安全 移动安全 个人信息安全 APP安全

队列Queue:任务间的消息读写,安排起来~

华为云开发者联盟

鸿蒙 数据结构 队列 Queue 消息

聊聊数据仓库建设

水滴

数据仓库 数仓 数仓架构 主数据管理 标签体系

技术上的过度医疗

superman

过度设计 完美方案

Python开发篇——构建虚拟Python开发环境(Conda+Poetry)

吴脑的键客

Python Anaconda

CRUD搬砖两三年了,怎么阅读Spring源码?

小傅哥

Java spring 小傅哥 源码学习 框架学习

filecoin云算力系统开发案例解析

获客I3O6O643Z97

挖矿矿池系统开发案例 fil币 fil矿机和云算力

教你如何将二进制文件导入到数据库

华为云开发者联盟

数据库 数据 二进制 GaussDB(DWS) 二进制文件

Axie区块链宠物游戏系统开发搭建

薇電13242772558

区块链

Go语言:SliceHeader,slice 如何高效处理数据?

微客鸟窝

Go 语言

钻石01:明心见性-如何由表及里精通线程池设计与原理

MetaThoughts

Java 多线程 并发

数据,流通在没有船的港口

白洞计划

微软亚研院:如何看待计算机视觉未来的走向?

百度开发者中心

最佳实践 方法论 计算机视觉 语言 & 开发 文化 & 方法

Python OpenCV Sobel 算子、Scharr 算子、laplacian 算子 复盘学习

梦想橡皮擦

Python 7月日更

Redis 帝国的神秘使者,竟然想改造 C 语言!

悟空聊架构

redis 架构 悟空聊架构 7月日更 用故事讲技术

三十岁,像培养孩子一样培养自己。

南冥

英特尔陈伟:AIoT时代的新思维

E科讯

架构实战营模块三作业

maybe

2021 挚物·AIoT产业领袖峰会召开,EMQ 映云科技喜获双料荣誉

EMQ映云科技

百度 华为 工业互联网 AIOT 边云协同

Spring Data与MongoDB:不协调的设计_DevOps & 平台工程_张龙_InfoQ精选文章