一、前言

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

        <dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.10.7.RELEASE</version>
</dependency>

pom.xml

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

@Configuration
@EnableMongoRepositories(basePackages = "org.springframework.data.mongodb",repositoryImplementationPostfix = "Impl") //启用MongoDB的Repository功能
@ComponentScan(basePackages = "org.springframework.data.mongodb")
@PropertySource("classpath:mongo.properties")
public class MongoConfig { /*
* MongoClientFactoryBean 工厂bean 会负责创建Mongo实例。
* */
@Bean(name = "mongo")
public MongoClientFactoryBean mongoClientFactoryBean(Environment env) {
MongoClientOptions.Builder builder = MongoClientOptions.builder();
MongoClientOptions build = builder.build();
MongoCredential credential = MongoCredential.createCredential(
env.getProperty("mongo.user", String.class),
env.getProperty("mongo.database", String.class),
env.getProperty("mongo.password", String.class).toCharArray());
MongoClientFactoryBean mongoClientFactoryBean = new MongoClientFactoryBean();
mongoClientFactoryBean.setHost(env.getProperty("mongo.host", String.class));
mongoClientFactoryBean.setPort(env.getProperty("mongo.port", Integer.class));
mongoClientFactoryBean.setCredentials(new MongoCredential[]{credential});
mongoClientFactoryBean.setMongoClientOptions(build);
return mongoClientFactoryBean;
} @Bean(name = "mongoTemplate")
public MongoTemplate mongoTemplate(Mongo mongo, Environment env) {
return new MongoTemplate(mongo, env.getProperty("mongo.database", String.class));
}
}

MongoConfig.java

3、applicationContext.xml XML配置方式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd"> <!--提供自动注入配置的扫描包-->
<context:component-scan base-package="org.springframework.data.mongodb"/> <context:property-placeholder location="classpath:mongo.properties" file-encoding="utf-8"/> <!--
1.mongo:连接配置
2.db-factory:相当于sessionFactory
3.mongoTemplate:与数据库接口交互的主要实现类
--> <mongo:mongo-client id="mongoClient" host="${mongo.host}" port="${mongo.port}" credentials="${mongo.user}:${mongo.password}@${mongo.database}">
<mongo:client-options
min-connections-per-host="${mongo.minConnectionsPerHost}"
threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}"
connect-timeout="${mongo.connectTimeout}"
max-wait-time="${mongo.maxWaitTime}"
socket-keep-alive="${mongo.socketKeepAlive}"
socket-timeout="${mongo.socketTimeout}"
max-connection-idle-time="${mongo.maxConnectionIdleTime}"
max-connection-life-time="${mongo.maxConnectionLifeTime}"
heartbeat-socket-timeout="${mongo.heartbeatSocketTimeout}"
heartbeat-connect-timeout="${mongo.heartbeatConnectTimeout}"
min-heartbeat-frequency="${mongo.minHeartbeatFrequency}"
heartbeat-frequency="${mongo.heartbeatFrequency}"/>
</mongo:mongo-client> <mongo:db-factory id="mongoDbFactory" dbname="${mongo.database}" mongo-ref="mongoClient"/> <!-- Spring提供的mongodb操作模板-->
<mongo:template id="mongoTemplate" db-factory-ref="mongoDbFactory" write-concern="NORMAL"/> <!-- mongodb bean的仓库目录,会自动扫描扩展了MongoRepository接口的接口进行注入 -->
<mongo:repositories base-package="org.springframework.data.mongodb" repository-impl-postfix="Impl"/>
</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中的键值。

@Document
public class Order { /**
* @ID 生成MongoDB文档的_id 内容,如果不指定,MongoDB 会主动生成一个
*/
@Id
private String id; /**
* @Field 映射成MongoDB文档的字段内容
*/
@Field("client")
private String customer; /**
* @Indexed 是否在该字段上加上索引
*/
@Indexed
private String type; /**
* 集合类型最好使用 ? 不确定类型(或者说任意类型)
* 否则会info(Found cycle for field 'itemList' in type 'Order' for path '')表明你的代码中有潜在的循环使用
*
* 像这样有另一个对象的集合,另一个对象不用加任何的MongoDB 注释
*/
private List<?> itemList = new ArrayList(); }

Order.java

三、MongoOperations

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

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

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

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

  • db.order.find({"client":"customer"})
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":"豪华型"})
Criteria criteria = Criteria.where("client").is("customer"); 
criteria.and("type").is("豪华型");
Query query = new Query(criteria);
  • db.order.find({"client":"customer","type":/^豪华/}) 正则表达式
Criteria criteria = Criteria.where("client").is("customer"); 
criteria.and("type").regex("^豪华");
Query query = new Query(criteria);
  • db.order.find({"client":"customer"}).sort({"type":-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) 分页
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);
  • 大于 小于 不等于
Criteria criteria = Criteria.where("client").is("customer");
criteria.and("key").lt(""); //小于
criteria.and("key").lte(""); //小于等于
criteria.and("key").gt(""); //大于
criteria.and("key").gte(""); //大于等于
criteria.and("key").ne(""); //不等于 mongoDB 没有 eq(等于) 这个操作
Query query = new Query(criteria);
  • $in $size $elemMatch $exists
List<String> list = new ArrayList();
Criteria condition = Criteria.where("x").lt(10).and("x").gt(5);
Criteria criteria = Criteria.where("client").is("customer");
criteria.and("key").in(list);
criteria.and("key").size(3); //匹配key数组长度等于 3 的文档
criteria.elemMatch(condition); //要求 x 的数组每个元素必须同时满足 大于5 小于10
criteria.and("key").exists(true);
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。

public interface OrderRepository extends MongoRepository<Order, String> {
/**
* 根据customer从文档中获取Order集合
* @param customer
* @return
*/
//@Query会接受一个JSON查询,而不是JPA查询。?0 表示第一个参数,?1 表示第二个参数,以此类推
// find这个查询动词并不是固定的。如果喜欢的话,我们还可以使用get作为查询动词:
@Query("{'customer':?0,'type':'type'}")
List<Order> findByCustomer(String customer); /**
* 根据customer 和 type 从文档中获取Order集合
* @param customer
* @param type
* @return
*/
List<Order> findByCustomerAndType(String customer, String type); /**
* 根据customer 和 type 从文档中获取Order集合(customer 在对比的时候使用的是like 而不是equals)
* @param customer
* @param type
* @return
*/
List<Order> findByCustomerLikeAndTypeLike(String customer, String type); }

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. 外网如何访问 Service?- 每天5分钟玩转 Docker 容器技术(139)

    除了 Cluster 内部可以访问 Service,很多情况我们也希望应用的 Service 能够暴露给 Cluster 外部.Kubernetes 提供了多种类型的 Service,默认是 Clus ...

  2. Android热修复技术原理详解(最新最全版本)

    本文框架 什么是热修复? 热修复框架分类 技术原理及特点 Tinker框架解析 各框架对比图 总结   通过阅读本文,你会对热修复技术有更深的认知,本文会列出各类框架的优缺点以及技术原理,文章末尾简单 ...

  3. Weex 初探

    Weex 初探 Weex 介绍 Weex 是阿里于 2016 年开源的一款开发框架,它的介绍是: Weex 是一个使用 Web 开发体验来开发高性能原生应用的框架. 它使用了 Web 技术来开发 An ...

  4. bzoj2969 矩形粉刷

    学习一波用markdown写题解的姿势QAQ 题意 给你一个w*h的矩形网格,每次随机选择两个点,将以这两个点为顶点的矩形内部的所有小正方形染黑,问染了k次之后期望有多少个黑色格子. 分析 一开始看错 ...

  5. [Luogu2463][SDOI2008]Sandy的卡片

    BZOJ权限题qwq Luogu sol "两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串" 其实就是差分一波以后完全相同 所以对输入的数据进行差分,同时记一下每一个 ...

  6. 【BZOJ1012】【JSOI2008】最大数(线段树)

    [JSOI2008]最大数 题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制:L不超过当前 ...

  7. 超文本传输​​协议 - HTTP / 1.1(Hypertext Transfer Protocol -- HTTP/1.1)之方法定义(Method Definitions)

    9方法定义 下面定义了HTTP / 1.1的一组常用方法.尽管可以扩展这个集合,但是另外的方法不能假定为单独扩展的客户端和服务器共享相同的语义. 主机请求头域(14.23节)必须伴随所有的HTTP / ...

  8. php 创建和修改文件内容

    file_put_contents写入文件 我们先来学习第一种写入文件的方式: int file_put_contents ( string $文件路径, string $写入数据]) 功能:向指定的 ...

  9. sqlserver中压缩日志文件

    最近在转移数据,sqlserver的日志文件ldf,占用空间特别大,为了还原库,节省空间,所以压缩日志文件迫在眉睫.在网上找了一段代码: USE [master] GO ALTER DATABASE ...

  10. 本地mysql无法连接原来是这里有问题啊。。。。。。

    1.怎么解决localhost无法链接本地mysql数据库问题_百度经验http://jingyan.baidu.com/article/d45ad14896d1cd69542b805c.html 2 ...