- 内容提要
- 序
- 前言
- 第一部分 背景知识
- 第 1 章 Spring Data 项目
- 第 2 章 Repository:便利的数据访问层
- 第 3 章 使用 Querydsl 实现类型安全的查询
- 第二部分 关系型数据库
- 第 4 章 JPA Repository
- 第 5 章 借助 Querydsl SQL 实现类型安全的 JDBC 编程
- 第三部分 NoSQL
- 第 6 章 MongoDB: 文档存储
- 第 7 章 Neo4j:图数据库
- 第 8 章 Redis:键/值存储
- 第四部分 快速应用开发
- 第 9 章 使用 Spring Roo 实现持久层
- 第 10 章 REST Repository 导出器
- 第五部分 大数据
- 第 11 章 Spring for Apache Hadoop
- 第 12 章 使用 Hadoop 分析数据
- 第 13 章 使用 Spring Batch 和 Spring Integration 创建大数据管道
- 第六部分 数据网格
- 第 14 章 分布式数据网格:GemFire
- 关于封面
6.5 Mongo Repository
如刚才所介绍,MongoOperations 接口提供了一份相当完整的 API 用来手动实现存储类。然而,我们可以使用第 2 章介绍的 Spring Data Repository 抽象进一步简化这个过程。接下来我们将讨论示例工程的 Repository 接口定义,并看看如何调用 Repository 方法。
6.5.1 搭建基础设施
使用 JavaConfig 注解(示例 6-34)或者 XML 命名空间元素来启用 Repository 机制。
示例 6-34 在 JavaConfig 中启用 Spring Data MongoDB Repository

在这个配置示例中,@EnableMongoRepositories 是最关键的部分。它将搭建 Repository 的基础设施,默认情况下会在配置类所在的包中扫描 Repository 接口。可以设置注解的 basePackage 或者 basePackageClasses 属性来对它进行调整。等效的 XML 配置也非常相似,但必须手动配置基础包(见示例 6-35)。
示例 6-35 在 XML 中启用 Spring Data MongoDB repository

6.5.2 Repository 详解
针对示例应用程序中的每一个 Repository,都有一个测试类,这些测试类可以基于本地 MongoDB 实例运行。它们会与 Repository 交互并调用暴露的方法。将日志的级别设置为 DEBUG,就可以看到实际的发现 Repository、执行查询等过程。
我们从最基本的 CustomerRepository 开始,如示例 6-36 所示。
示例 6-36 CustomerRepository 接口

前面两个方法是 CURD 方法,并且会被路由到通用类 SimpleMongoRepository 上,这个类提供了所声明的方法。第 2 章已说明过它的通用机制,所以在这里真正有意思的方法是 findByEmailAddress(…)。由于没有定义手工查询,所以将会引入查询的衍生机制,它将解析方法并据此推导出查询。因为引用了 emailAddress 属性,衍生出的查询逻辑就会是 emailAddress = ?0。因此,基础设施会使用 Spring Data MongoDB 的查询 API 建立 Query 实例。它会依次把属性引用转换成对应的字段映射,因此我们最终所使用的查询就是{ email : ?0 }。在方法调用的时候,给定的参数将会和查询绑定在一起并最终执行。
下一个 Repository 是 ProductRepository,如示例 6-37 所示。
示例 6-37 ProductRepository 接口

首先请注意 ProductRepository 继承了 CrudRepository 而不是普通的 Repository 接口。这样 CRUD 方法会引入到 Repository 定义中。因此,不需要手动的定义 findOne(…) 和 save(…) 方法。和 CustomerRepository.findByEmailAddress(…) 类似,findByDescription Containing(…) 再次使用了衍生查询机制。与前一个方法不同的地方在于它使用 Containing 关键字来限制断言,这会将传入的描述参数放到一个正则表达式之中,从而限制描述信息能够匹配给定的 String。
第二个要注意的是分页 API 的使用(见 2.2.3 小节“分页与排序”)。客户端可将 Pageable 传入到方法中,从而将返回结果限制为特定的某一页,Pageable 中包含了页码和每页大小的信息,如示例 6-38 所示。返回 Page 对象中包括了结果集以及一些元信息,如全部页数等。可以在 ProductRepositoryIntegration 的 lookupProductsByDescription() 方法中看到这个方法的使用示例。
示例 6-38 使用 findByDescriptionContaining(…) 方法

首先,我们将 PageRequest 设为要请求第一页,分页大小为 1,结果集需要按照 name 降序排列。可以看到它返回的 Page 对象不仅包含了结果集,还包括所返回的页在全部页中的位置信息。
第二个方法(回到示例 6-37)在定义时使用 @Query 注解来手动定义 MongoDB 查询。当查询衍生机制没有提供我们需要的功能或查询方法的名称非常冗长时,它是非常方便的。我们构建了一个通用的查询{ ?0 : ?1 },将方法的第一个参数当作键而第二个参数作为值。现在客户端可以使用这个方法来查询含有特定属性的 Product(例如,基座连接器插头),如示例 6-39 所示。
示例 6-39 查询有基座连接器插头的 Product

正如所预期的,这个方法调用返回了 iPod 基座。通过这样的方法,业务逻辑基于匹配的属性(连接器插头与插座)很容易就能实现产品的推荐功能。
最后但同样重要的是 OrderRepository(见示例 6-40)。我们已经讨论两个 Repository 接口了,最后一个并没有太大的差别。
示例 6-40 OrderRepository 接口

这里所定义的方法只是简单地使用了查询衍生机制。与前面的 Repository 接口相比,不同的地方在于所扩展的接口,它继承了 PagingAndSortingRepository,这样不仅暴露了 CRUD 方法,还有许多其他的方法,例如 findAll(Pageable pageable),借助这个方法能够对所有的 Order 进行分页操作。更多关于分页的通用 API,可以参见 2.2.3 小节“分页与排序”。
6.5.3 Mongo Querydsl 集成
我们已经知道如何将查询方法添加到 Repository 接口中了,接下来看看如何使用 Querydsl 为实体动态地创建断言,并通过 Repository 抽象来执行。第 3 章中提供了 Querydsl 是什么以及它如何工作的概要介绍。如果已经阅读过 4.4.2 小节“Repository Querydsl 集成”,就会看到即使我们查询完全不同的存储形式,API 的设置以及使用都是非常相似的。
为了生成元模型类,在 pom.xml 文件中配置了 Querydsl 的 Maven 插件,如示例 6-41 所示。
示例 6-41 为 MongoDB 设置 Querydsl APT 处理器

与 JPA 方式唯一不同的是,我们配置了 MongoAnnotationProcessor。它会设置 APT 处理器,它会检查 Spring Data MongoDB 映射模块提供的注解,以正确地产生元模型。除此之外,还提供了一个集成方式,让 Querydsl 在创建 MongoDB 查询时,能够识别映射以及可能已注册的自定义转换器。
有的断言是基于生成的元模型类所构建的,为了执行这些断言需要将相关的 API 包含进来,因此 ProductRepository 还继承了 QueryDslPredicateExecutor(见示例 6-42)。
示例 6-42 ProductRepository 接口继承了 QueryDslPredicateExecutor

QuerydslProductRepositoryIntegrationTest 展现了如何使用断言。同样的,这段代码几乎百分之百复制了 JPA 中的代码。通过执行 product.name.eq("iPad") 的断言得到了一个 iPad 的引用,并根据产品的描述进行查找以验证断言执行所得到的结果,如示例 6-43 所示。
示例 6-43 使用 Querydsl 断言查询 Product

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论