Java实战操作MongoDB集群(副本集)

Spring提供了MongoDB操作的工具:MongoTemplate,使得在Spring环境下对MongoDB的操作更为便利,本章我们就来学一下如何用MongoTemplate对MongoDB的集群环境(副本集)做操作;

实战环境选用Docker

本次实战,Web工程和MongoDB都运行在Docker环境的容器中,这么做是为了快速搭建环境,不要在环境上花费太多时间,更聚焦Java开发;

Java源码

本次实战的java工程的源码我已经上传到github了,地址是:git@github.com:zq2599/blog_demos.git,里面有多个工程,本次实战的工程是mongodbreplicationdemo,如下图红框所示:

环境规划

本次实战的环境是一个Tomcat server和Mongodb集群(副本集),我们将在Docker下部署这些server,所以一共要运行以下四个容器:

容器名

ip

备注

m0

172.18.0.2

MongoDB Primary

m1

172.18.0.3

MongoDB Secondary1

m2

172.18.0.4

MongoDB Secondary2

tomcat001

172.18.0.5

Tomcat server

相互关系如下图:

关于Tomcat server环境

本次实战我们用Maven创建一个java web工程,然后在线部署到Docker上去,Tomcat的镜像请用bolingcavalry/online_deploy_tomcat:0.0.1,关于在线部署的详情请参照文章《实战docker,编写Dockerfile定制tomcat镜像,实现web应用在线部署》

关于MongoDB集群环境

搭建MongoDB副本集的集群环境不是本章的重点,这篇文章详细的记录了如何搭建集群环境,您可以作为实战参考:《Docker下,实战mongodb副本集(Replication)》

docker-compose.yml配置

由于要启动四个容器:Mongodb集群和Tomcat Server,所以用docker-compose批量管理比较方便,docker-compose.yml内容如下:

version: '2'
services:
  m0: 
    image: bolingcavalry/ubuntu16-mongodb349:0.0.1
    container_name: m0
    command: /bin/sh -c 'mongod --replSet replset0'
    restart: always
  m1: 
    image: bolingcavalry/ubuntu16-mongodb349:0.0.1
    container_name: m1
    depends_on:
      - m0
    command: /bin/sh -c 'mongod --replSet replset0'
    restart: always
  m2: 
    image: bolingcavalry/ubuntu16-mongodb349:0.0.1
    container_name: m2
    depends_on:
      - m1
    command: /bin/sh -c 'mongod --replSet replset0'
    restart: always
  tomcat001: 
    image: bolingcavalry/online_deploy_tomcat:0.0.1
    container_name: tomcat001
    ports: 
    - "8080:8080" 
    links: 
      - m0:mongodb0
      - m1:mongodb1
      - m2:mongodb2
    restart: always

如上述yml脚本所示,m0、m1、m2这三个容器组成了副本集集群,tomcat001容器配置的link属性中包含了其他三个容器,所以原本需要直接使用IP地址的地方都可以用mongodb0、mongodb1、mongodb2来代替了;

启动容器,把集群环境配置好

在docker-compose.yml文件所在目录下,执行命令docker-compose up -d批量启动所有容器,再进入m0容器把集群环境配置好,配置方法非常简单,请参考《Docker下,实战mongodb副本集(Replication)》

终于,准备工作已经完成,咱们可以开始编码了;

依赖库

在我们的pom.xml中,除了常规的spring依赖,还要加入本次用到的MongoDB操作的依赖:

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

另外为了更方便的查看数据,我们把fastjson的依赖也引进来:

<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.39</version>
    </dependency>

资源文件

工程用到的资源文件一共四个,如下图:

  1. config.properties 放的是MongoDB集群的所有机器地址和端口,以及要连接的数据库:
mongodb.host=mongodb0:27017,mongodb1:27017,mongodb2:27017
mongodb.dataname=school

如上所示,机器地址并没有用IP,而是link参数中的alias:mongodb0,mongodb1,mongodb2; 2. logback.xml 日志配置,不细说了; 3. spring-extends.xml 这里面存放的是操作MongoDB所需的配置信息,mongoTemplate这个bean负责提供操作MongoDB的服务,请注意更改xmlns:mongo和xsi:schemaLocation的配置,负责会导致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-3.1.xsd  
                            http://www.springframework.org/schema/context  
                            http://www.springframework.org/schema/context/spring-context-3.1.xsd
                            http://www.springframework.org/schema/data/mongo
                            http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
                            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
    <!-- 自动扫描 -->
    <context:component-scan base-package="com.bolingcavalry" />

    <!-- mongodb配置 -->
    <context:property-placeholder location="classpath:config.properties"/>

    <!--集群-->
    <mongo:mongo id="replicaSetMongo" replica-set="${mongodb.host}">
        <!-- 每个IP的连接数-->
        <mongo:options connections-per-host="10"
                       threads-allowed-to-block-for-connection-multiplier="5"
                       auto-connect-retry="true"/>
    </mongo:mongo>

    <!--给应用用到的-->
    <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg name="mongo" ref="replicaSetMongo" />
        <!--mongo的数据库名称-->
        <constructor-arg name="databaseName" value="${mongodb.dataname}" />
    </bean>
</beans>

在业务代码中通过AutoWire引入mongoTemplate,就能操作MongoDB了; 5. spring-mvc.xml Spring环境的常规配置,不用多说了;

此外还有web.xml文件也要注意,要将spring-extends.xml引入:

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-extends.xml</param-value>
    </context-param>

代码结构

代码结构如下图所示,我们通过浏览器发起的增删改查操作都会由MongodbController来处理,它会调用StudentService接口的服务,和数据库有关的实体类是Student:

Student实体类

实体类没什么好说的,主要是注意Document注解,说明了该类是student集合对应的实体类:

@Document(collection = "student")
public class Student {
    /**
     * 学号
     */
    private String id;

    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

    ......

服务实现类,操作MongoDB的核心代码

下面是通过提供的API对MongoDB进行增删改查的代码:

@Autowired
    MongoTemplate mongoTemplate;

    /**
     * 新增一个文档
     * @param student
     * @return
     */
    public String insert(Student student) {
        LOGGER.info("start insert : {}", JSON.toJSONString(student));
        mongoTemplate.insert(student);
        LOGGER.info("finish insert");

        return null;
    }

    /**
     * 根据名称删除文档
     * @param name
     * @return
     */
    public String deleteByName(String name) {
        LOGGER.info("start delete [{}]", name);
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("name").is(name);
        query.addCriteria(criteria);
        mongoTemplate.findAndRemove(query, Student.class);
        return null;
    }

    /**
     * 根据名称修改student文档的年龄字段
     * @param student
     * @return
     */
    public String updateByName(Student student) {
        LOGGER.info("start update [{}]", JSON.toJSONString(student));
        //构造查询信息
        Query query = buildNameQuery(student.getName());

        //构造更新信息
        Update update = new Update();
        update.set("age", student.getAge());

        //执行更新
        mongoTemplate.updateFirst(query, update, Student.class);

        return null;
    }

    /**
     * 查找student集合的所有文档
     * @return
     */
    public List<Student> findAll() {
        return mongoTemplate.findAll(Student.class);
    }

    /**
     * 创建一个根据名字查询的Query对象
     * @param name
     * @return
     */
    private Query buildNameQuery(String name){
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("name").is(name);
        query.addCriteria(criteria);

        return query;
    }

Controller对Service的调用

此处Controller的作用是受到web请求后直接调用Service提供的API来完成数据库操作:

    @Autowired
    StudentService studentService;

    @RequestMapping("/insert")
    public String insert(HttpServletRequest request, Model model) {
        String errorStr = studentService.insert(buildStudent(request));

        LOGGER.info("student insert service response [{}]", errorStr);

        return StringUtils.isEmpty(errorStr) ? "success" : buileFilePageInfo(errorStr, model);
    }

    @RequestMapping("/delete")
    public String delete(HttpServletRequest request, Model model) {
        String name = get(request, "name");

        String errorStr = studentService.deleteByName(name);

        LOGGER.info("student deleteByName service response [{}]", errorStr);

        return StringUtils.isEmpty(errorStr) ? "success" : buileFilePageInfo(errorStr, model);
    }

    @RequestMapping("/update")
    public String update(HttpServletRequest request, Model model) {
        String errorStr = studentService.updateByName(buildStudent(request));
        LOGGER.info("student updateByName service response [{}]", errorStr);
        return StringUtils.isEmpty(errorStr) ? "success" : buileFilePageInfo(errorStr, model);
    }

    @RequestMapping("/findall")
    @ResponseBody
    public String findAll(HttpServletRequest request, Model model) {
        List<Student> list = studentService.findAll();

        return (null!=list && !list.isEmpty())
                ? JSON.toJSONString(list)
                : "empty";
    }

部署

代码写好了,pom.xml所在目录下执行mvn clean package -U -Dmaven.test.skip=true tomcat7:redeploy在线部署到Tomcat server,然后一起来验证一下吧;

验证

在浏览器输入http://localhost:8080/mongodbreplicationdemo/findall查看所有数据,会看到以下结果,表明查处的结果为空:

新增一条记录试试,输入http://localhost:8080/mongodbreplicationdemo/insert?name=Tom&age=11,提示操作成功:

再查看就有数据了:

执行这个请求更新Tom的年龄:http://localhost:8080/mongodbreplicationdemo/update?name=Tom&age=33

再看看年龄已经更新成功了:

最后是删除操作:http://localhost:8080/mongodbreplicationdemo/delete?name=Tom

本次实战的java工程的源码我已经上传到github了,地址是:git@github.com:zq2599/blog_demos.git,里面有多个工程,本次实战的工程是mongodbreplicationdemo,如下图红框所示:

至此,Java操作MongoDB的实战就结束了,我们对MongoTemplate算是有了初步的认识,更多的功能应该是配合着MongoDB的功能以及实际场景的需求逐渐浮出水面,大家一起尝试和探索吧。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java Edge

Tomcat架构解析之2 connector BIOHTTP11ProtocolMapperCoyoteAdapter

3325
来自专栏匠心独运的博客

消息中间件—RabbitMQ(集群监控篇1)

摘要:任何没有监控的系统上线,一旦在生产环境发生故障,那么排查和修复问题的及时性将无法得到保证

1013
来自专栏大魏分享(微信公众号:david-share)

从一张图看Devops全流程

一、持续交付工具链全图 ? 上图源自网络。上图很清晰地列出了CD几个阶段使用的工具。 CD的工具链很长,但并不是每个模块所有工具都那么流行;换言之,我们在每个模...

9969
来自专栏阿杜的世界

Spring Cloud学习-Eureka、Ribbon和Feign引子实践源码下载参考资料

看完《微服务设计》后,算是补上了自己在服务化这块的理论知识,在业界,一般有两种微服务的实践方法:基于dubbo的微服务架构、基于Spring Cloud的微服务...

1192
来自专栏cloudskyme

hadoop使用(五)

第1章 引言 1.1 编写目的 对关于hadoop的文档及资料进行进一步的整理。 1.2 相关网站    毋庸置疑 http://hadoop.apache.o...

3175
来自专栏软件工程师成长笔记

springboot集成ActiveMQ

732
来自专栏伦少的博客

Spark Streaming连接Kafka入门教程

转载请务必注明原创地址为:https://dongkelun.com/2018/05/17/sparkKafka/

47210
来自专栏aoho求索

基于可靠消息方案的分布式事务(四):接入Lottor服务

在上一篇文章中,通过Lottor Sample介绍了快速体验分布式事务Lottor。本文将会介绍如何将微服务中的生产方和消费方服务接入Lottor。

1401
来自专栏IT可乐

RabbitMQ详解(二)------消息通信的概念

  说到消息通信,可能我们首先会想到的是邮箱,QQ,微信,短信等等这些通信方式,这些通信方式都有发送者,接收者,还有一个中间存储离线消息的容器。但是这些通信方式...

1113
来自专栏bboysoul

使用colloide扫描网站后台

在渗透测试的时候我们通常要找一个网站的后台,但是有时候网站的后台并不是特别好找,比如我们学校的那个垃圾网站,今天用到的工具叫colloide,它是一款利用字典扫...

754

扫码关注云+社区