CentOS 7.6 64bit 安装 搭建 MongoDB单机副本集 配置Spring Boot 开启事务 全过程

安装主程序

Linux安装包下载地址:CSDN码云

上传压缩包到Linux中,解压到当前目录:

[root@centos ~]# tar -xvf mongodb-linux-x86_64-4.0.10.tgz

移动解压后的文件夹到指定的目录中:

[root@centos ~]# mv mongodb-linux-x86_64-4.0.10 /usr/local/mongodb

到这MongoDB就已经安装完成了,接下来创建log日志的文件夹和数据文件夹,以及配置文件

添加配置文件

MongoDB需要搭建副本集才可以在springboot中使用事务,而MongoDB搭建副本集最少需要3个节点:主节点、副本节点、仲裁节点

创建主节点

建立存放数据和日志的目录

[root@centos ~]# mkdir -p /mongodb/replica_sets/myrs_27017/log
[root@centos ~]# mkdir -p /mongodb/replica_sets/myrs_27017/data/db

新建或修改配置文件:

vim /mongodb/replica_sets/myrs_27017/mongod.conf

myrs_27017 内容如下(需要修改bindIp为服务器内网ip):

systemLog:
   #MongoDB发送所有日志输出的目标指定为文件
   destination: file
   #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
   path: "/mongodb/replica_sets/myrs_27017/log/mongod.log"
   #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
   logAppend: true
storage:
   #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
   dbPath: "/mongodb/replica_sets/myrs_27017/data/db"
   journal:
      #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
      enabled: true
processManagement:
   #启用在后台运行mongos或mongod进程的守护进程模式。
   fork: true
   #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
   pidFilePath: "/mongodb/replica_sets/myrs_27017/log/mongod.pid"
net:
   #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
   #bindIpAll: true
   #服务实例绑定的IP,默认是localhost,如果是云服务器,需要再加一个内网ip
   bindIp: localhost,10.0.16.5
   #绑定的端口,默认是27017
   port: 27017
replication:
   #副本集的名称
   replSetName: myrs

启动节点服务:

[root@centos ~]# /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27017/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 54257
child process started successfully, parent exiting

创建副本节点

建立存放数据和日志的目录

[root@centos ~]# mkdir -p /mongodb/replica_sets/myrs_27018/log
[root@centos ~]# mkdir -p /mongodb/replica_sets/myrs_27018/data/db

新建或修改配置文件:

vim /mongodb/replica_sets/myrs_27018/mongod.conf

myrs_27018内容如下(需要修改bindIp为服务器内网ip):

systemLog:
   #MongoDB发送所有日志输出的目标指定为文件
   destination: file
   #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
   path: "/mongodb/replica_sets/myrs_27018/log/mongod.log"
   #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
   logAppend: true
storage:
   #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
   dbPath: "/mongodb/replica_sets/myrs_27018/data/db"
   journal:
      #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
      enabled: true
processManagement:
   #启用在后台运行mongos或mongod进程的守护进程模式。
   fork: true
   #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
   pidFilePath: "/mongodb/replica_sets/myrs_27018/log/mongod.pid"
net:
   #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
   #bindIpAll: true
   #服务实例绑定的IP,默认是localhost,如果是云服务器,需要再加一个内网ip
   bindIp: localhost,10.0.16.5
   #绑定的端口,默认是27017
   port: 27018
replication:
   #副本集的名称
   replSetName: myrs

启动节点服务:

[root@centos ~]# /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27018/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 54257
child process started successfully, parent exiting

创建仲裁节点

建立存放数据和日志的目录

[root@centos ~]# mkdir -p /mongodb/replica_sets/myrs_27019/log
[root@centos ~]# mkdir -p /mongodb/replica_sets/myrs_27019/data/db

新建或修改配置文件:

vim /mongodb/replica_sets/myrs_27019/mongod.conf

myrs_27019 内容如下(需要修改bindIp为服务器内网ip):

systemLog:
   #MongoDB发送所有日志输出的目标指定为文件
   destination: file
   #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
   path: "/mongodb/replica_sets/myrs_27019/log/mongod.log"
   #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
   logAppend: true
storage:
   #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
   dbPath: "/mongodb/replica_sets/myrs_27019/data/db"
   journal:
      #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
      enabled: true
processManagement:
   #启用在后台运行mongos或mongod进程的守护进程模式。
   fork: true
   #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
   pidFilePath: "/mongodb/replica_sets/myrs_27019/log/mongod.pid"
net:
   #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
   #bindIpAll: true
   #服务实例绑定的IP,默认是localhost,如果是云服务器,需要再加一个内网ip
   bindIp: localhost,10.0.16.5
   #绑定的端口,默认是27017
   port: 27019
replication:
   #副本集的名称
   replSetName: myrs

启动节点服务:

[root@centos ~]# /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27019/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 54257
child process started successfully, parent exiting

初始化配置副本集和主节点

使用客户端命令连接任意一个节点,但这里尽量要连接主节点(27017节点):

[root@centos ~]# /usr/local/mongodb/bin/mongo --port=27017

结果,连接上之后,很多命令无法使用,,比如 show dbs 等,必须初始化副本集才行
准备初始化新的副本集:

> rs.initiate()

查看副本集的配置内容

> rs.conf()

将27018的副本节点添加到副本集中,这边ip写公网ip

rs.add("42.192.214.60:27018")

将27019的仲裁节点添加到副本集中:

rs.addArb("42.192.214.60:27019")

Ctrl+c退出来,进入副本节点

[root@centos ~]# /usr/local/mongodb/bin/mongo --port=27018

在副本节点承认自己是副本节点

> rs.slaveOk()

同样Ctrl+c退出来,进入仲裁节点

[root@centos ~]# /usr/local/mongodb/bin/mongo --port=27019

在仲裁节点承认自己是仲裁节点

> rs.slaveOk()

Ctrl+c退出来,再重新进入主节点

[root@centos ~]# /usr/local/mongodb/bin/mongo --port=27017

查看副本集配置,发现主节点是内网ip

myrs:PRIMARY> rs.conf()

更改为外网ip

var config = rs.config();config.members[0].host="42.192.214.60:27017";rs.reconfig(config)

安全认证

通过主节点添加一个管理员帐号

开启认证之前,创建超管用户:myroot,密码:123456(随意)

myrs:PRIMARY> use admin
switched to db admin
myrs:PRIMARY> db.createUser({user:"myroot",pwd:"123456",roles:["root"]})
Successfully added user: { "user" : "myroot", "roles" : [ "root" ] }

创建完退出

创建副本集认证的key文件

生成一个key文件到当前文件夹中。可以使用任何方法生成密钥文件。例如,以下操作使用openssl生成密码文件

[root@centos ~]# openssl rand -base64 90 -out ./mongo.keyfile

然后使用chmod来更改文件权限,仅为文件所有者提供读取权限

[root@centos ~]# chmod 400 ./mongo.keyfile

查看

[root@centos ~]# ll mongo.keyfile
-r-------- 1 root root 122 Jan 27 23:35 mongo.keyfile

复制到各个节点下:

[root@centos ~]# cp mongo.keyfile /mongodb/replica_sets/myrs_27017
[root@centos ~]# cp mongo.keyfile /mongodb/replica_sets/myrs_27018
[root@centos ~]# cp mongo.keyfile /mongodb/replica_sets/myrs_27019

追加配置文件:
vi /mongodb/replica_sets/myrs_27017/mongod.conf

security:
   #KeyFile鉴权文件
   keyFile: /mongodb/replica_sets/myrs_27017/mongo.keyfile
   #开启认证方式运行
   authorization: enabled

vi /mongodb/replica_sets/myrs_27018/mongod.conf

security:
   #KeyFile鉴权文件
   keyFile: /mongodb/replica_sets/myrs_27018/mongo.keyfile
   #开启认证方式运行
   authorization: enabled

vi /mongodb/replica_sets/myrs_27019/mongod.conf

security:
   #KeyFile鉴权文件
   keyFile: /mongodb/replica_sets/myrs_27019/mongo.keyfile
   #开启认证方式运行
   authorization: enabled

重启:

[root@VM-16-5-centos ~]# ps -ef |grep mongod
[root@VM-16-5-centos ~]# kill -2 6996 7202 7384

分别启动副本集节点:

/usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27017/mongod.conf
/usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27018/mongod.conf
/usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27019/mongod.conf

连接主节点:

[root@VM-16-5-centos ~]# /usr/local/mongodb/bin/mongo --port=27017

在主节点上添加普通账号:

#先用管理员账号登录
#切换到admin库
use admin
#管理员账号认证
db.auth("myroot","123456")
#切换到要认证的库
use articledb
#添加普通用户
db.createUser({user: "bobo", pwd: "123456", roles: ["readWrite"]})

SpringDataMongoDB连接副本集

yml配置

spring:
  #mongodb数据源配置
  data:
    mongodb:
      #mongodb://账号:密码@ip:端口/数据库
      uri: mongodb://bobo:123456@180.76.159.126:27017,180.76.159.126:27018,180.76.159.126:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs

副本集语法:‘username:password@hostname/dbname’ 格式,'username’为用户名,‘password’ 为密码。

mongodb://username:password@host1,host2,host3/articledb?connect=replicaSet&slaveOk=true&replicaSet=副本集名字

引入依赖

        <!-- mongodb -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

实体类:

package cn.itcast.article.po;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

import java.io.Serializable;


/**
 * 文章评论实体类
 * 其实下面的注解可以全都不写,都有默认值
 */
//把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档。
//@Document(collection="mongodb 对应 collection 名")
// 若未加 @Document ,该 bean save 到 mongo 的 comment collection
// 若添加 @Document ,则 save 到 comment collection
@Document(collection="comment")//可以省略,如果省略,则默认使用类名小写映射集合
//复合索引
@CompoundIndex( def = "{'userid': 1, 'nickname': -1}")
public class Comment implements Serializable {
    //主键标识,该属性的值会自动对应mongodb的主键字段"_id",如果该属性名就叫“id”,则该注解可以省略,否则必须写
    @Id
    private String id;
    //该属性对应mongodb的字段的名字,如果一致,则无需该注解
    @Field("content")
    private String content;

    //添加了一个单字段的索引
    @Indexed
    private String userid;
    private String nickname;
 
}

操作基类

package com.windlight.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.windlight.constants.CfgConstants;
import com.windlight.pojo.base.MongoSuperModel;
import com.windlight.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;

/**
 * 基类
 * 继承类和接口类是自定义的,可以不用
 * CfgConstants.MONGO_ID  就是“_id”,mongo里的id是_id
 */
@Service
public abstract class BaseServiceImpl<T extends MongoSuperModel> implements BaseService<T> {
    @Autowired
    protected MongoTemplate mongoTemplate;

    @Override
    public T insert(T t) {
        t.create();
        return mongoTemplate.save(t);
    }

    @Override
    public void deleteById(String id) {
        Query query = new Query(Criteria.where(CfgConstants.MONGO_ID).is(id));
        mongoTemplate.remove(query, (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    }

    @Override
    public void updateById(T t) {
        String id = t.getId();
        t.setId(null);
        t.update();
        Map<String, Object> params = BeanUtil.beanToMap(t, false, true);
        Update update = new Update();
        for (String key : params.keySet()) {
            Object o = params.get(key);
            if (null != o) {
                update.set(key, o);
            }
        }
        Query query = new Query(Criteria.where(CfgConstants.MONGO_ID).is(id));
        mongoTemplate.updateFirst(query, update, (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
        t.setId(id);
    }

    @Override
    public T selectById(String id) {
        Query query = new Query(Criteria.where(CfgConstants.MONGO_ID).is(id));
        return mongoTemplate.findOne(query, (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    }

    @Override
    public List<T> find(Map<String, Object> search) {
        //查询条件
        Query query = new Query();
        if (search != null) {
            for (String key : search.keySet()) {
                if ("isPage".equals(key)
                        || "pageNum".equals(key)
                        || "pageSize".equals(key)) {
                    continue;
                }
                Object o = search.get(key);
                if (null != o) {
                    query.addCriteria(Criteria.where(key).is(o));
                }
            }
            //分页
            if (Boolean.TRUE.equals(search.get("isPage"))) {
                Integer pageNum = (Integer) search.get("pageNum");
                Integer pageSize = (Integer) search.get("pageSize");
                query.skip((long) (pageNum - 1) * pageSize).limit(pageSize);
            }
        }
        //排序
        query.with(Sort.by(Sort.Direction.DESC, CfgConstants.CREATE_TIME));
        return mongoTemplate.find(query, (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    }
}

创建配置类,开启事务:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.MongoTransactionManager;

@Configuration
public class TransactionConfig {

    @Bean
    MongoTransactionManager transactionManager(MongoDbFactory factory) {
        return new MongoTransactionManager(factory);
    }

}

创建service ,在方法上加@Transactional注解,即可在报错后回滚

Java中使用MongoDB:


Query query = new Query();
     
    //单条件
    [where("表(集合)中的字段名").is(传入的数据)]
    query.addCriteria(Criteria.where("UserId").is(1))//多条件
    query.addCriteria(Criteria.where("UserId").is(1).and("username").is("wangwu"))//模糊条件
    [toUserIds="*.?"+(传入的参数)+"*.?"]
    query.addCriteria(Criteria.where("UserId").regex(UserIds))//条件(范围)
    query.addCriteria(Criteria.where("UserId").in(UserIdList));
    
    //时间段
    query.addCriteria(Criteria.where("Time").gte("开始时间段").lte("终止时间段");
    
    //排序       
    query.with(new Sort(Sort.Direction.DESC/ASC,"字段名"));
    
    //分页
    query.skip(0).limit(1);
    
    //调用 例如
    mongoTemplate.findOne(query, 实体类.class);
    //全查 全删
     mongoTemplate.find(query, 实体类.class);
     mongoTemplate.remove(query, 实体类.class);
    
    //改
    //要修改的数据
    Query query = new Query(Criteria.where("username").is("zhangsan"));
        //设置修改的字段
        Update update = new Update();
        update.set("age",100);
        update.set("address","上海浦东区");
    //调用
    mongoTemplate.upsert(query,update,实体类.class);



版权声明:本文为qq_41720396原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。