HarmonyOS开发者限时福利来啦!最高10w+现金激励等你拿~ 了解详情
写点什么

MongoDB、Java 及 ORM

  • 2012-05-22
  • 本文字数:6026 字

    阅读完需:约 20 分钟

MongoDB 简介

目前有很多互相竞争的 NoSQL 产品,它们使用的方式不尽相同,但都能很好地解决大数据问题。 MongoDB 就是其中一款非常不错的产品。MongoDB 是面向文档、无 Schema 的存储解决方案,它用 JSON 风格的文档展现、查询、修改数据。

MongoDB 有很丰富的文档,安装和设置都很简单,而且易于扩展。它支持大家熟知的复制、分片、索引和 Map/Reduce 等概念。MongoDB 开源社区的规模很大,也很活跃。让 MongoDB 引以为豪的是,包括 Disney、Craigslist、Foursquare、Github 和 SourceForge 在内的大型、高流量生产环境都已经部署了 MongoDB。MongoDB 是个开源项目,由 DoubleClick 前高管们创办的 10gen.com 公司创建和维护。除了很积极地参与社区支持外,10gen 也提供商业支持。

MongoDB 和 NoSQL 的优劣势

作为 NoSQL 解决方案,MongoDB 的优势是很容易上手。在我第一次深入研究 NoSQL 数据库的时候,尝试了很多基于 Java 的解决方案,我发现要搞清楚什么是列族(column family)、Hadoop 和 HBase 之间是什么关系、ZooKeeper 到底是什么非常费时间。我最终想明白这些问题的时候,才明白 Cassandra、HBase 等产品都是非常完善的 NoSQL 解决方案。和其他解决方案相比,MongoDB 则更容易掌握一些,开始写代码之前不需要理解太多的概念。

很显然,MongoDB 和任何软件一样都存在缺陷。在学习、使用 MongoDB 的过程中,我遇到过几件可算是“陷阱”的事情:

  • 不要把它用成 RDBMS。这一点看起来显而易见,但在 MongoDB 里创建、执行复杂查询都很容易,以至于到了想用它做实时查询的时候,你可能才会发现自己已经做过头了,而且可能会碰到性能问题。(我以前就犯过这样的错)
  • MongoDB 的索引是 Binary Tree。如果你不太熟悉 B-Tree,应该研究一下。查询条件的顺序要和创建索引的顺序相匹配。
  • 精心设计索引。这和前面提到的 B-Tree 有关系。我刚开始创建的几个索引都包含文档里的很多字段,因为总是想着以后可能会查询它们,这种想法你应该能够理解。不要犯这样的错误。我曾给一个很小的集合(大约一千万条记录)创建了一个索引,这个索引后来增长到 17GB,比集合本身还要大。如果某个数组字段可能会包含成百上千的条目,你可能不会给它创建索引。
  • MongoDB 支持 NoSQL 的方法非常有趣,它用 BSON 存储、用 JSON 表示,管理和 Map/Reduce 则用了 JavaScript。这样一来,等 MongoDB 发展的时间足够久、和更流行的大数据解决方案一样长的时候,MongoDB 必然会出现一些奇怪的小问题,比如在 NumberLong 上使用等于运算符会判断失败

MongoDB、控制台、驱动程序

MongoDB 的管理通常可以在一个 JavaScript 客户端控制台应用上进行,控制台应用能简化数据迁移和操作等复杂任务;你也完全可以用 JavaScript 语言编程实现 MongoDB 的管理。在这篇文章里,我们会示范控制台的使用。现在的 MongoDB 客户端产品非常多,它们都具备能投入生产环境的品质,MongoDB 社区也称它们为驱动程序。一般来说,每种编程语言都有各自的驱动程序,这些驱动程序能覆盖所有流行的编程语言,还有一些并不是很流行的编程语言。本文将展示 MongoDB 的 Java 驱动程序该如何使用,也会和使用 ORM 库(MJORM)的方式进行比较。

MJORM 简介:MongoDB 的 ORM 解决方案

NoSQL 数据存储还有很多有趣的问题需要解决,最近让应用程序员比较关心的是对象关系映射(ORM)。ORM 是指持久化数据和应用所用对象之间的映射,持久化数据过去都存储在关系型数据库里。ORM 能让处理数据的过程更加流畅、更加贴近编写应用的语言。

MongoDB 面向文档的架构让它很容易进行 ORM,因为它存储的文档本身就是对象。不过可惜的是,可用于 MongoDB 的 Java ORM 库还不是很多,目前只有 morphia (针对 MongoDB 的 Java 库,是类型安全的)和 spring-data (Spring Data 综合项目的 MongoDB 实现)。

这些 ORM 库使用了大量注解,出于很多原因,我并不倾向于使用注解,其中最重要的是被注解的对象在多个项目之间的可移植性问题。所以我创建了 mongo-Java-orm 项目(MJORM,发音为 me-yorm),它是针对 MongoDB 的 Java ORM。MJORM 使用 MIT 许可,放在了 Google Code 上。项目用 Maven 构建,Maven 的工件库目前托管在 Google Code 的 Subversion 服务器上。写这篇文章的时候,MJORM 最新的稳定发布版本是 0.15,个别项目已经在生产环境里使用了。

MJORM 入门

将 MJORM 库添加到项目里

Maven 用户首先要将 MJORM 的 Maven 仓库添加到 pom.xml 文件里,以便自己的项目能使用 MJORM 工件:

复制代码
<repository>
<id>mjorm-webdav-maven-repo</id>
<name>mjorm maven repository</name>
<url>http://mongo-Java-orm.googlecode.com/svn/maven/repo/</url>
<layout>default</layout>
</repository>

然后添加依赖本身:

复制代码
<dependency>
<groupid>com.googlecode</groupid>
<artifactid>mongo-Java-orm</artifactid>
<version>0.15</version>
</dependency>

这样你就能把 MJORM 类导入到自己的应用里并使用它们。如果你没用 Maven,那你需要手动下载 MJORM 库,还有 MJORM pom.xml 里列出的所有依赖。

创建 POJO

依赖关系处理好之后,就开始编写代码吧。我们先编写 Java POJO:

复制代码
class Author {
private String firstName;
private String lastName;
// ... setters and getters ...
}
class Book {
private String id;
private String isbn;
private String title;
private String description;
private Author author;
// ... setters and getters ...
}

上面的对象模型描述了作者和书,作者有一个 ID、还有姓氏和名字,书的描述信息则包含 ID、ISBN 号、标题、描述信息和作者。

可以看到书的 ID 属性是一个 String,它会适应成 MongoDB 的 ObjectId 类型,ObjectId 类型是个十二字节的二进制值,用十六进制的字符串来表示。虽然 MongoDB 要求所有集合里的每个文档都要有一个唯一的 ID,但并没有要求 ID 必须是 ObjectId 类型。目前 MJORM 支持的 ID 类型只有 ObjectId,而且会把它们表示成 String。

你可能已经注意到,Author 对象没有 ID。这是因为 Author 是 Book 文档的子文档,所以就没必要非得有一个 ID 了。请记住,MongoDB 的 ID 只需要放在一个集合的根级别文档中。

创建 XML 映射文件

下一步是创建 XML 映射文件,MJORM 会用这些映射文件把 MongoDB 文档映射成对象。在本文的演示里,我们会给两个对象各创建一个文档,但真正合理的做法是把所有的映射都放在一个 XML 文件里,或者根据实际需要进行分割。

下面是 Author.mjorm.xml:

复制代码
<?xml version="1.0"?>
<descriptors>
<object class="Author">
<property name="firstName" />
<property name="lastName" />
</object>
</descriptors>

Book.mjorm.xml 是:

复制代码
<?xml version="1.0"?>
<descriptors>
<object class="Book">
<property name="id" id="true" auto="true" />
<property name="isbn" />
<property name="title" />
<property name="description" />
<property name="author" />
</object>
</descriptors>

映射文件完全能自解释。descriptors 元素是根元素,所有的映射文件都要有。根元素下面是 object 元素,用来定义要被映射到 MongoDB 文档的类。object 会包含 property 元素,用来描述 POJO 的所有属性,以及它们怎样映射到 MongoDB 文档的属性。property 元素至少要有一个 name 属性,这是 POJO 属性的名称,也是 MongoDB 文档属性的名称。property 元素还可以添加一个 column 属性,指定 MongoDB 文档里备用的属性名称。

包含 id 属性的 property 元素会被看作是对象的唯一标识符。一个 object 元素可以只包含一个带有 id 属性的 property 元素。auto 属性是让 MJORM 在持久化这个属性时给它自动生成一个值。

要想了解有关 XML 映射文件更详细的说明,请移步至 Google Code 上的 MJORM 项目。

整合

我们现在已经创建好了数据模型,还有告诉 MJORM 在数据写入 MongoDB 时如何解析 POJO、从 MongoDB 读取数据时如何封装 POJO 的映射文件,那我们就可以开始一段有趣的学习之旅了。首先我们必须打开到 MongoDB 的连接:

复制代码
Mongo mongo = new Mongo(
new MongoURI("mongodb://localhost/mjormIsFun")); // 10gen 驱动程序

Mongo 对象来自 10gen 员工编写的 Java 驱动程序。这个例子打开了一个到本地 MongoDB 实例的连接,使用 mjormIsFun 数据库。接下来我们创建 MJORM 里的 ObjectMapper。目前 MJORM 里可用的 ObjectMapper 接口实现只有 XmlDescriptorObjectMapper,它使用前面的 XML Schema,MJORM 以后的实现可能会支持注解或其他配置机制。

复制代码
XmlDescriptorObjectMapper objectMapper = new XmlDescriptorObjectMapper();
mapper.addXmlObjectDescriptor(new File("Book.mjorm.xml"));
mapper.addXmlObjectDescriptor(new File("Author.mjorm.xml"));

我们创建了 XmlDescriptorObjectMapper 对象,并添加了映射文件。下一步我们会创建一个 MJORM 提供的 MongoDao 对象实例:

复制代码
DB db = mongo.getDB("mjormIsFun"); // 10gen 驱动程序
MongoDao dao = new MongoDaoImpl(db, objectMapper);

我们先获取了一个 10gen 驱动程序里的 DB 对象实例。然后用 DB 对象和先前创建的 ObjectMapper 来创建 MongoDao。现在已经做好了持久化数据的准备,那让我们创建一个 Book 对象,并把它保存到 MongoDB 里去。

复制代码
Book book = new Book();
book.setIsbn("1594743061");
book.setTitle("MongoDB is fun");
book.setDescription("...");
book = dao.createObject("books", book);
System.out.println(book.getId()); // 4f96309f762dd76ece5a9595

我们先创建了 Book 对象,赋值之后调用了 MongoDao 的 createObject 方法,两个参数分别是集合名称“books”和 Book 对象。MJORM 接着会用先前创建的 XML 映射文件把 Book 转换成 DBObject(10gen 的 Java 驱动程序所使用的基本对象类型),并把新的文档持久化到“books”集合中。然后 MJORM 会返回 Book 对象的实例,返回的 Book 对象实例带有生成的 id 属性。重点要注意的是,MongoDB 在默认情况下并不会要求创建好数据库或集合后才能使用;MongoDB 在需要的时候才会创建它们,这有时候会引起混乱。从 MongoDB 控制台上看到的新 Book 如下所示:

复制代码
> db.books.find({_id:ObjectId("4f96309f762dd76ece5a9595")}).pretty()
{
"_id": ObjectId("4f96309f762dd76ece5a9595"),
"isbn": "1594743061",
"title": "MongoDB is fun",
"description": "..."
}

让我们来看看如果不使用 MJORM,而是直接用 10gen 的 Java 驱动程序,createObject 的过程是怎样的:

复制代码
Book book = new Book();
book.setIsbn("1594743061");
book.setTitle("MongoDB is fun");
book.setDescription("...");
DBObject bookObj = BasicDBObjectBuilder.start()
.add("isbn", book.getIsbn())
.add("title", book.getTitle())
.add("description", book.getDescription())
.get();
// ‘db’是我们先前创建的 DB 对象
DBCollection col = db.getCollection("books");
col.insert(bookObj);
ObjectId id = ObjectId.class.cast(bookObj.get("_id"));
System.out.println(id.toStringMongod()); // 4f96309f762dd76ece5a9595

现在我们来查询一下对象:

复制代码
Book book = dao.readObject("books", "4f96309f762dd76ece5a9595", Book.class);
System.out.println(book.getTitle()); // "MongoDB is fun"

readObject 方法用指定的 id 从特定集合中读取文件,然后将文件转换成相应的类(会再次使用先前的映射文件)并返回。

敏锐的你可能已经察觉到我们的 Book 还没 Author,但 Book 仍然被持久化了。这正是 MongoDB 的无 Schema 特性。除了 id 之外,我们不能要求集合里的文档包含任何属性,所以在 MongoDB 里创建没有 Author 的 Book 是完全没有问题的。让我们给 Book 添加一位 Author 并更新:

复制代码
Author author = new Author();
author.setFirstName("Brian");
author.setLastName("Dilley");
book.setAuthor(author);
dao.updateObject("books", "4f96309f762dd76ece5a9595", book);

现在的 Book 包含了 Author,也持久化到了 MongoDB。让我们从 MongoDB 控制台上看看新的 Book:

复制代码
> db.books.find({_id:ObjectId("4f96309f762dd76ece5a9595")}).pretty()
{
"_id": ObjectId("4f96309f762dd76ece5a9595"),
"isbn": "1594743061",
"title": "MongoDB is fun",
"description": "..."
"author": {
"firstName": "Brian",
"lastName": "Dilley"
}
}

正如你所看到的,持久化的 Book 现在包含一个作者。接着再看看不使用 MJORM 的情况:

复制代码
Author author = new Author();
author.setFirstName("Brian");
author.setLastName("Dilley");
book.setAuthor(author);
DBObject bookObj = BasicDBObjectBuilder.start()
.add("isbn", book.getIsbn())
.add("title", book.getTitle())
.add("description", book.getDescription())
.push("author")
.add("firstName", author.getFirstName())
.add("lastName", author.getLastName())
.pop()
.get();
DBCollection col = db.getCollection("books");
col.update(new BasicDBObject("_id", bookObj.get("_id")), bookObj);

在这篇文章里我们就不深入介绍 MongoDao 的所有方法了。如果你想在项目里使用 MJORM,推荐你看看 MJORM 项目的文档,或者是 MJORM 项目提供的 MongoDao 接口。

结论

希望这篇文章能让大家对 MongoDB 和 MJORM 开始感兴趣。方兴未艾的 MongoDB 是个很优秀的 NoSQL 数据存储产品,有很多很不错的特性。如果你要在 Java 项目里使用 MongoDB,那你可以考虑用 MJORM 库来满足 ORM 需求。要是能提出功能需求、Bug 报告、文档,或给源码打补丁,我们将不胜感激!

作者介绍

Brian Dilley是一位经验丰富的高级工程师,带过十三年的团队,他的技术专长有 Java、Java EE、Spring Framework、Linux 内部原理和管理。Brian 曾单枪匹马创立了好几家互联网公司,并维护着它们的产品。他还擅长 IaaS、云、PHP、Linux 管理,以及生产环境和公司里软硬件基础设施的安装、配置,比如负载均衡、数据库、Web 等。你可以在 Twitter 上 Follow Brian

查看英文原文: MongoDB, Java and Object Relational Mapping

译者后记:

MongoDB 并不是一款关系型数据库,针对文中的 ORM 这个词语,读者 Roopesh Shenoy 提出:

用 ORM 描述 MJORM 框架似乎并不合适——毕竟没有关系型数据库! 也许我们可以使用其他名称?Database Mapper?

Jean-Baptiste DUSSEAUT 回复到:

在我创建的项目里,我管它叫对象文件映射(Object Document Mapper)

读者朋友们,你们对此有什么看法呢?


给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2012-05-22 00:0016375
用户头像

发布了 151 篇内容, 共 61.8 次阅读, 收获喜欢 18 次。

关注

评论

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

文心一言 VS 讯飞星火 VS chatgpt (97)-- 算法导论9.3 3题

福大大架构师每日一题

福大大架构师每日一题

小项目想当大Boss? 你该读读《孙子兵法》 | 京东云技术团队

京东科技开发者

项目管理 项目经理 企业号9月PK榜

OpenHarmony创新赛 | 您有一份创新激励奖待领取 请查收!

OpenHarmony开发者

OpenHarmony

CocoaPods 在iOS开发中养活了这么多项目,它到底是个啥? | 京东云技术团队

京东科技开发者

ios CocoaPods 移动开发 企业号9月PK榜

新生产力范式,重塑工作效率

百度开发者中心

人工智能 ChatGPT 生成式AI

openEuler与Linaro携手参加OSSUMMIT 2023

openEuler

Linux 开源 openEuler 资讯

蓝易云:Linux下更新curl版本教程!

百度搜索:蓝易云

云计算 Linux 运维 云服务器 curl

中移链交易模块介绍

BSN研习社

乙烯裂解工艺可视化2D组态系统

2D3D前端可视化开发

物联网 组态软件 工业组态 乙烯裂解工艺 乙烯裂解组态图

蓝易云:【Linux工具】-yum/gdb使用教程!

百度搜索:蓝易云

云计算 运维 gdb yum 云服务器

一文给你讲清楚BeanFactory 和 FactoryBean 的关联与区别

华为云开发者联盟

spring 开发 华为云 华为云开发者联盟 企业号9月PK榜

开源框架中的责任链模式实践

vivo互联网技术

dubbo 设计模式 sentinel 责任链

openEuler 亮相全球顶级开源盛会 OSSUMMIT 2023,持续推动智能化未来的实现

openEuler

Linux 开源 openEuler 资讯

浅入深出的微前端MicroApp | 京东云技术团队

京东科技开发者

前端 React 微前端 企业号9月PK榜

大连英歌石科技公司与华为云签署盘古大模型大连实验室框架合作协议

新消费日报

三步实现BERT模型迁移部署到昇腾

华为云开发者联盟

人工智能 华为云 昇腾 华为云开发者联盟 企业号9月PK榜

ELT in ByteHouse 实践与展望

字节跳动数据平台

数据库 大数据 云原生 数仓 企业号9月PK榜

亮相华为全联接大会,用友荣获“华为云技术领航最佳实践伙伴”奖项

用友BIP

华为云

喜讯!云起无垠获评软件供应链安全技能竞赛“团队优秀奖”

云起无垠

搜索技术领域的“奥林匹克”,飞桨支持“第二届百度搜索创新大赛”正式启动!

飞桨PaddlePaddle

百度 飞桨 AI Studio

Mobpush上线跨时区推送功能,助力中国开发者应用出海

MobTech袤博科技

智能推送 跨时区 app运营 应用出海

站群服务器提升多网站管理效率的不二之选

一只扑棱蛾子

站群服务器

DAPP区块链公链代币智能合约质押挖矿系统开发

l8l259l3365

数据驱动创新,应用场景广泛

百度开发者中心

人工智能 数据分析 生成式AI 千帆大模型平台

PWA建快应用,小程序建超级App?

没有用户名丶

上升到人生法则的贝叶斯理论

小魏写代码

Cinema 4D 2024 for mac(c4d2024) v2024.0.1永久激活版

mac

windows 三维建模软件 苹果mac Cinema 4D 2024 c4d2024

HarmonyOS创作激励计划启动:助力技术创作突破边界

HarmonyOS开发者

HarmonyOS

慢SQL原因分析之索引失效 | 京东物流技术团队

京东科技开发者

MySQL 数据库 sql 索引失效 企业号9月PK榜

传媒软件的未来变革与发展趋势

百度开发者中心

传媒 生成式AI 千帆大模型平台

MongoDB、Java及ORM_Java_Brian C. Dilley_InfoQ精选文章