CentOS 7.6 64bit安装搭建MongoDB单机副本集全过程
安装主程序
上传压缩包到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);