一、前言

MongoDB是最为流行的开源文档数据库之一。Spring Data MongoDB提供了三种方式在Spring应用中使用MongoDB:

  • 通过注解实现对象-文档映射;
  • 使用MongoTemplate实现基于模板的数据库访问;
  • 自动化的运行时Repository生成功能。

二、集成实现

1. 启用MongoDB

为了有效的使用Spring Data MongoDB,我们需要在Spring配置中添加几个必要的bean。首先,我们需要配置MongoClient,用它来创建Mongo实例,以便于访问MongoDB数据库。在这里,我们使用Spring Data MongoDB的MongoFactoryBean更加简单。因为它是一个工厂bean,会负责构建Mongo实例,而且不用处理MongoClient构造器所抛出的UnknownHostException异常。同时,我们还需要有一个MongoTemplate bean,实现基于模板的数据库访问。此外,不是必须,但是强烈推荐启用Spring Data MongoDB的自动化Repository生成功能。

1、pom.xml

  1. <dependency>
  2. <groupId>org.springframework.data</groupId>
  3. <artifactId>spring-data-mongodb</artifactId>
  4. <version>1.10.7.RELEASE</version>
  5. </dependency>

pom.xml

2、MongoConfig.java 配置类配置方式

  1. @Configuration
  2. @EnableMongoRepositories(basePackages = "org.springframework.data.mongodb",repositoryImplementationPostfix = "Impl") //启用MongoDB的Repository功能
  3. @ComponentScan(basePackages = "org.springframework.data.mongodb")
  4. @PropertySource("classpath:mongo.properties")
  5. public class MongoConfig {
  6.  
  7. /*
  8. * MongoClientFactoryBean 工厂bean 会负责创建Mongo实例。
  9. * */
  10. @Bean(name = "mongo")
  11. public MongoClientFactoryBean mongoClientFactoryBean(Environment env) {
  12. MongoClientOptions.Builder builder = MongoClientOptions.builder();
  13. MongoClientOptions build = builder.build();
  14. MongoCredential credential = MongoCredential.createCredential(
  15. env.getProperty("mongo.user", String.class),
  16. env.getProperty("mongo.database", String.class),
  17. env.getProperty("mongo.password", String.class).toCharArray());
  18. MongoClientFactoryBean mongoClientFactoryBean = new MongoClientFactoryBean();
  19. mongoClientFactoryBean.setHost(env.getProperty("mongo.host", String.class));
  20. mongoClientFactoryBean.setPort(env.getProperty("mongo.port", Integer.class));
  21. mongoClientFactoryBean.setCredentials(new MongoCredential[]{credential});
  22. mongoClientFactoryBean.setMongoClientOptions(build);
  23. return mongoClientFactoryBean;
  24. }
  25.  
  26. @Bean(name = "mongoTemplate")
  27. public MongoTemplate mongoTemplate(Mongo mongo, Environment env) {
  28. return new MongoTemplate(mongo, env.getProperty("mongo.database", String.class));
  29. }
  30. }

MongoConfig.java

3、applicationContext.xml XML配置方式

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:mongo="http://www.springframework.org/schema/data/mongo"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
  8. http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd">
  9.  
  10. <!--提供自动注入配置的扫描包-->
  11. <context:component-scan base-package="org.springframework.data.mongodb"/>
  12.  
  13. <context:property-placeholder location="classpath:mongo.properties" file-encoding="utf-8"/>
  14.  
  15. <!--
  16. 1.mongo:连接配置
  17. 2.db-factory:相当于sessionFactory
  18. 3.mongoTemplate:与数据库接口交互的主要实现类
  19. -->
  20.  
  21. <mongo:mongo-client id="mongoClient" host="${mongo.host}" port="${mongo.port}" credentials="${mongo.user}:${mongo.password}@${mongo.database}">
  22. <mongo:client-options
  23. min-connections-per-host="${mongo.minConnectionsPerHost}"
  24. threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}"
  25. connect-timeout="${mongo.connectTimeout}"
  26. max-wait-time="${mongo.maxWaitTime}"
  27. socket-keep-alive="${mongo.socketKeepAlive}"
  28. socket-timeout="${mongo.socketTimeout}"
  29. max-connection-idle-time="${mongo.maxConnectionIdleTime}"
  30. max-connection-life-time="${mongo.maxConnectionLifeTime}"
  31. heartbeat-socket-timeout="${mongo.heartbeatSocketTimeout}"
  32. heartbeat-connect-timeout="${mongo.heartbeatConnectTimeout}"
  33. min-heartbeat-frequency="${mongo.minHeartbeatFrequency}"
  34. heartbeat-frequency="${mongo.heartbeatFrequency}"/>
  35. </mongo:mongo-client>
  36.  
  37. <mongo:db-factory id="mongoDbFactory" dbname="${mongo.database}" mongo-ref="mongoClient"/>
  38.  
  39. <!-- Spring提供的mongodb操作模板-->
  40. <mongo:template id="mongoTemplate" db-factory-ref="mongoDbFactory" write-concern="NORMAL"/>
  41.  
  42. <!-- mongodb bean的仓库目录,会自动扫描扩展了MongoRepository接口的接口进行注入 -->
  43. <mongo:repositories base-package="org.springframework.data.mongodb" repository-impl-postfix="Impl"/>
  44. </beans>

applicationContext.xml

2. 注解实现对象文档映射

Spring Data MongoDB 提供了一套对象-文档 映射的注解。

@Document - 用于类,以表示这个类需要映射到数据库,您也可以指定映射到数据库的集合名称
@Id - 用于字段级别,标记这个字段是一个主键,默认生成的名称是“_id”
@DBRef - 用于字段,以表示它将使用com.mongodb.DBRef进行存储。
@Indexed - 用于字段,表示该字段需要如何创建索引
@CompoundIndex - 用于类,以声明复合索引
@GeoSpatialIndexed - 用于字段,进行地理位置索引
@TextIndexed - 用于字段,标记该字段要包含在文本索引中
@Field - 用于字段,并描述字段的名称,因为它将在MongoDB BSON文档中表示,允许名称与该类的字段名不同。
@Version - 用于字段锁定,保存操作时检查修改。初始值是0,每次更新时自动触发。
@Language - 用于字段,以设置文本索引的语言覆盖属性。
@Transient - 默认情况下,所有私有字段都映射到文档,此注解将会去除此字段的映射
@PersistenceConstructor - 标记一个给定的构造函数,即使是一个protected修饰的,在从数据库实例化对象时使用。构造函数参数通过名称映射到检索的DBObject中的键值。

  1. @Document
  2. public class Order {
  3.  
  4. /**
  5. * @ID 生成MongoDB文档的_id 内容,如果不指定,MongoDB 会主动生成一个
  6. */
  7. @Id
  8. private String id;
  9.  
  10. /**
  11. * @Field 映射成MongoDB文档的字段内容
  12. */
  13. @Field("client")
  14. private String customer;
  15.  
  16. /**
  17. * @Indexed 是否在该字段上加上索引
  18. */
  19. @Indexed
  20. private String type;
  21.  
  22. /**
  23. * 集合类型最好使用 ? 不确定类型(或者说任意类型)
  24. * 否则会info(Found cycle for field 'itemList' in type 'Order' for path '')表明你的代码中有潜在的循环使用
  25. *
  26. * 像这样有另一个对象的集合,另一个对象不用加任何的MongoDB 注释
  27. */
  28. private List<?> itemList = new ArrayList();
  29.  
  30. }

Order.java

三、MongoOperations

我们已经配置好了MongoTemplate,接下来,需要做的就是将其注入到使用它的地方。注意,在这里我们将MongoTemplate注入到一个类型为MongoOperations的属性中。MongoOperations 是 MongoTemplate 所实现的接口,不直接使用具体实现是一个好的习惯。

1、 MongoOperations 暴露了多个使用MongoDB文档数据库的方法。这里介绍几个最为常用的操作:

  • 计算集合的数量
  1. long order = mongoOperations.getCollection("order").count();
  • 保存文档
  1. Order order = new Order(); mongoOperations.save(order, "order");
  • 根据文档的 _id 查找文档
  1. Order byId = mongoOperations.findById("5abb2a6303238760a48e3fd2", Order.class);
  • 得到所有文档
  1. List<Order> all = mongoOperations.findAll(Order.class);
  • 删除文档
  1. Order order = new Order(); order.setId("1"); mongoOperations.remove(order);

2、 不过 MongoOperations 最常见的用法还是接受一个 Query 对象作为参数进行查询、修改、删除的操作。这里简单介绍一些 Query 和 Criteria 的语法:

  • db.order.find({"client":"customer"})
  1. Criteria criteria = Criteria.where("client").is("customer");
    Query query = new Query(criteria);
    List<Order> orders = mongoOperations.find(query, Order.class);
  • db.order.find({"client":"customer","type":"豪华型"})
  1. Criteria criteria = Criteria.where("client").is("customer");
    criteria.and("type").is("豪华型");
    Query query = new Query(criteria);
  • db.order.find({"client":"customer","type":/^豪华/}) 正则表达式
  1. Criteria criteria = Criteria.where("client").is("customer");
    criteria.and("type").regex("^豪华");
    Query query = new Query(criteria);
  • db.order.find({"client":"customer"}).sort({"type":-1}) 排序
  1. Criteria criteria = Criteria.where("client").is("customer");
    Sort sort = new Sort(Sort.Direction.DESC,"type");
    Query query = new Query(criteria).with(sort);
    List<Order> orders = mongoOperations.find(query, Order.class);
  • db.order.find({"client":"customer"}).skip(5).limit(5) 分页
  1. Criteria criteria = Criteria.where("client").is("customer");
    /*limit 是pageSize , skip 是 第几页*pageSize */
    Query query = new Query(criteria).skip(5).limit(5);
    List<Order> orders = mongoOperations.find(query, Order.class);
  • 大于 小于 不等于
  1. Criteria criteria = Criteria.where("client").is("customer");
  2. criteria.and("key").lt(""); //小于
  3. criteria.and("key").lte(""); //小于等于
  4. criteria.and("key").gt(""); //大于
  5. criteria.and("key").gte(""); //大于等于
  6. criteria.and("key").ne(""); //不等于 mongoDB 没有 eq(等于) 这个操作
  7. Query query = new Query(criteria);
  • $in $size $elemMatch $exists
  1. List<String> list = new ArrayList();
  2. Criteria condition = Criteria.where("x").lt(10).and("x").gt(5);
  3. Criteria criteria = Criteria.where("client").is("customer");
  4. criteria.and("key").in(list);
  5. criteria.and("key").size(3); //匹配key数组长度等于 3 的文档
  6. criteria.elemMatch(condition); //要求 x 的数组每个元素必须同时满足 大于5 小于10
  7. criteria.and("key").exists(true);
  8. Query query = new Query(criteria);

 3、 MongoOperations 还有许多聚合函数、地理空间 的用法......这里就不介绍了,接下来的文章会提到。

四、MongoDB Repository

Spring Data JPA Repository 有一个神奇的功能 —— 创建一个接口,我们只要按照一定的命名规则编写接口的方法,Spring Data JPA能够自动创建接口的实现。Spring Data MongoDB 当然也有这个特性,让我们来看看怎么实现吧!

我们已经通过@EnableMongoRepositories注解启用了Spring Data MongoDB的Repository功能(或者通过xml配置的方式),接下来需要做的就是创建一个接口,Repository实现要基于这个接口来生成。不过,在这里,我们不再扩展JpaRepository,而是要扩展MongoRepository。

  1. public interface OrderRepository extends MongoRepository<Order, String> {
  2. /**
  3. * 根据customer从文档中获取Order集合
  4. * @param customer
  5. * @return
  6. */
  7. //@Query会接受一个JSON查询,而不是JPA查询。?0 表示第一个参数,?1 表示第二个参数,以此类推
  8. // find这个查询动词并不是固定的。如果喜欢的话,我们还可以使用get作为查询动词:
  9. @Query("{'customer':?0,'type':'type'}")
  10. List<Order> findByCustomer(String customer);
  11.  
  12. /**
  13. * 根据customer 和 type 从文档中获取Order集合
  14. * @param customer
  15. * @param type
  16. * @return
  17. */
  18. List<Order> findByCustomerAndType(String customer, String type);
  19.  
  20. /**
  21. * 根据customer 和 type 从文档中获取Order集合(customer 在对比的时候使用的是like 而不是equals)
  22. * @param customer
  23. * @param type
  24. * @return
  25. */
  26. List<Order> findByCustomerLikeAndTypeLike(String customer, String type);
  27.  
  28. }

OrderRepository.jave

既然扩展了 MongoRepository 接口,OrderRepository 自然而然的有了许多对Order文档进行CRUD操作的方法实现。

像这种用法怎么用呢?比如我们前面要查询一个文档,很自然的写了一个Query条件用来查询。但是我们现在不用了,定义一个接口方法就可以了!连实现都不用!因为 Spring Data JPA 能够自动创建接口的实现。

上面的代码用了@Query 注解。@Query注解可以为Repository方法指定自定义的查询。@Query能够像在JPA中那样用在MongoDB上。唯一的区别在于针对MongoDB时,@Query会接受一个JSON查询,而不是JPA查询。

五、结语

之前单纯的以为MongoDB只是一个像Oracle、MySQL那样存储数据的数据库。今天才发现自己犯了个大大的错误,像市面上的打车软件的范围派单、叫餐软件的附近商家,都是通过MongoDB 的一个查询就搞定了。MongoDB 提供了很多地理位置逻辑的API......感觉又发现了一块新大陆呀!

源代码地址:https://github.com/JMCuixy/SpringDataMongoDB

MongoDB系列三(Spring集成方案).的更多相关文章

  1. Spring Boot系列(三) Spring Boot 之 JDBC

    数据源 类型 javax.sql.DataSource javax.sql.XADataSource org.springframework.jdbc.datasource.embedded,Enbe ...

  2. Struts1.X与Spring集成——第一种方案

    spring+struts(第一种方案) 集成原理:在Action中取得BeanFactory,通过BeanFactory取得业务逻辑对象,调用业务逻辑方法. 一,新建一个项目Spring_Strut ...

  3. Spring Boot进阶系列三

    Thymeleaf是官方推荐的显示引擎,这篇文章主要介绍怎么让spring boot整合Thymeleaf.  它是一个适用于Web和独立环境的现代服务器端Java模板引擎. Thymeleaf的主要 ...

  4. Spring系列之新注解配置+Spring集成junit+注解注入

    Spring系列之注解配置 Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率 你本来要写一段很长的代码来构造一个 ...

  5. Activiti工作流学习(三)Activiti工作流与spring集成

    一.前言 前面Activiti工作流的学习,说明了Activiti的基本应用,在我们开发中可以根据实际的业务参考Activiti的API去更好的理解以及巩固.我们实际的开发中我们基本上都使用sprin ...

  6. MyBatis学习系列三——结合Spring

    目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring MyBatis在项目中应用一般都要结合Spring,这一章主要把MyBat ...

  7. spring集成mongodb jar包版本问题

    在开发过程中,spring集成mongodb的jar包. 如果需要使用排序功能. spring-data-mongodb-1.4.1.RELEASE.jar 的版本为1.4.1,如果使用如下代码: Q ...

  8. spring集成mongodb封装的简单的CRUD

    1.什么是mongodb         MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. mongoDB MongoDB是一个介 ...

  9. Spring+Struts集成(方案一)

    SSH框架是现在非常流行的框架之一,本文接下来主要来对Spring和Struts的集成进行展示. 集成原理:在Action中取得BeanFactory,通过BeanFactory取得业务逻辑对象. 集 ...

随机推荐

  1. 芝麻HTTP:Python爬虫利器之Xpath语法与lxml库的用法

    安装 ​pip install lxml 利用 pip 安装即可 XPath语法 XPath 是一门在 XML 文档中查找信息的语言.XPath 可用来在 XML 文档中对元素和属性进行遍历.XPat ...

  2. spoj freetour II

    昨天吐槽还没A,今天就A了 有个变量开成了全局变量,应该携程局部变量 对于中间的solve我也不懂为什么是nlog2n,我不看题解也不会做 #include<bits/stdc++.h> ...

  3. e.preventDefault()和e.stopPropagation()以及return false的作用和区别

    前段时间开发中,遇到一个父元素和子元素都有事件时,发现会出现事件冒泡现象,虽然知道ev.stopPropagation()和ev.preventDefault()其中一个是阻止事件冒泡和阻止默认行为, ...

  4. spring的PathVariable和value={}小技巧(shiro项目中来的三)

    <property name="successUrl" value="/main/index" /> @RequestMapping(value=& ...

  5. Linux入门——开机启动过程浅析

    Linux开机启动过程浅析 Introduction 开机启动过程分为以下6个步骤,分别是BIOS, MBR, GRUB, Kernel, Init, RunLevel, RunDefinition ...

  6. SAXParser解析xml文件

    对于xml的解析,这里学习并演示使用SAXParser进行解析的样例. 使用此种方法无法解析"gb2312"编码的xml文件,因此,此处xml文件编码设置为"UTF-8& ...

  7. Android中的Socket

    1. UDP (1)访问网络必须添加权限,访问网络必须添加权限,访问网络必须添加权限,重要的事情说三遍. (2)简述 UDP协议是面向报文的,简单地说,利用UDP访问网络的步骤就是"寄快递& ...

  8. POJ 1087 A Plug for UNIX (网络流,最大流)

    题面 You are in charge of setting up the press room for the inaugural meeting of the United Nations In ...

  9. 【CJOJ2499】【DP合集】棋盘 chess

    Description 给出一张 n × n 的棋盘,格子有黑有白.现在要在棋盘上放棋子,要求: • 黑格子上不能有棋子 • 每行每列至多只有一枚棋子 你的任务是求出有多少种合法的摆放方案.答案模 1 ...

  10. [SPOJ]DISUBSTR:Distinct Substrings&[SPOJ]SUBST1:New Distinct Substrings

    题面 Vjudge Vjudge Sol 求一个串不同子串的个数 每个子串一定是某个后缀的前缀,也就是求所有后缀不同前缀的个数 每来一个后缀\(suf(i)\)就会有,\(len-sa[i]+1\)的 ...