面向文档的NoSQL数据库,用于大量数据存储
专用名词:
1、数据库 - show dbs(databases) 包含多个集合
1、集合 collection 包含多个文档
2、文档 :集合中的记录,文档包含多个字段名称和值
3、字段:JSON的名称
4、游标:执行查询结果集的指针
5、JSON 文档中存储的数据格式
####二、为什么用?
1、非常灵活,可以适应实际的业务环境和需求
2、支持多种查询
3、支持索引,提高搜索性能
4、副本集、高可用
5、负载均衡、分片
RDBMS | MongoDB | |
---|---|---|
Table | Collection | RDBMS - 表;MongoDB - 集合 |
Row | Document | RDBMS - 数据行;MongoDB - 文档 |
Column | Field | RDBMS - 数据列;MongoDB - 字段 |
JOIN | Embedded Document | RDBMS - 关联查询;MongoDB - 内嵌文档 |
类型 | 实现 |
---|---|
关系型数据库 | MySQL、Oracle、SQL Server |
基于键值对 | Redis、DynamoDB、Memcached |
大数据存储(聚合查询高性能) | Cassandra、Hbase、Hypertable |
基于Hadoop生态 | Hive、Spark |
面向文档(JSON/XML) | MongoDB、CouchDB、Amazon SimpleDB |
基于图形(社交网络、物流、空间数据) | Neo4J、Infinite Graph、OrientDB、FlockDB |
快速检索 | lucence、Solr、Elasticsearch |
ACID:
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
CAP:
强一致性(Consistency)
可用性(Availability)
分区容错性(Partition tolerance)
CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
CP - 满足一致性,分区容忍的系统,通常性能不是特别高。(ZK集群)
AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。(Redis集群)BASE:
基本可用(Basically Available)
软状态(Soft state)
最终一致性(Eventually consistent)
下载安装包
解压安装包
tar -zxvf mongodb-linux-x86_64-rhel62-4.0.23.tgz
创建mongodb数据文件夹
mkdir data
mkdir logs
mkdir conf
创建文件
cd ./logs
touch mongdb.log
cd ../conf/
touch mongodb.conf
编写配置文件
vim mongodb.conf
输入一下内容
#数据库路径
dbpath=/xx/xxx/mongodb/mongo/data
#日志输出文件路径
logpath=/xx/xxx/mongodb/mongo/logs/mongodb.log
#错误日志采用追加模式
logappend=true
#启用日志文件,默认启用
journal=true
#这个选项可以过滤掉一些无用的日志信息,若需要调试使用请设置为false
quiet=true
#端口号 默认为27017
port=27017
#允许远程访问
bind_ip=0.0.0.0
#开启子进程
fork=true
#开启认证,必选先添加用户
auth=true
配置环境变量
vim /etc/profile
添加内容
export PATH=$PATH:/xx/xxx/mongodb/mogon/bin
生效配置文件
source /etc/profile
启动 mongo服务
./mongod -f /xx/xxx/mongodb/mongo/conf/mongodb.conf
或者
./mongod --config /xx/xxx/mongodb/mongo/conf/mongodb.conf
查看服务是否正常启动
netstat -lanp | grep 27017
或者
ps -ef | grep mongo
连接mongo服务
./mongo
./mongo --host=127.0.0.1 --port=27017
添加用户认证
>use admin
>db.createUser({user:"root",pwd:"123456",roles[{role:"root",db:"admin"}]})
>db.shutdowServer()
认证
>use admin
>db.auth('root','123456')
>show dbs
工具连接
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OQi0sNRs-1624682480475)(./auth.jpg)]
操作手册
创建(不存在会自动创建并切换到该库,存在则切换到该库)
use 数据库名
>use shadow
查看
>db
>show dbs
>show databases
删除(use 到当前库然后执行)
>db.dropDatabase()
修复
./mongod --repair --dbpath=./data
操作手册
创建
显式
db.createCollection(集合名称)
>db.createCollection("shop")
隐式(没有shop集合会自动创建)
>db.shop.insert({x:1})
删除 (db.集合名称.drop())
>db.shop.drop()
查看
>show collections
操作手册
新增
db.集合名称.insert()
db.集合名称.insertOne()
db.集合名称.save() #通过传入的文档来替换已有文档,_id 主键存在就更新,不存在就插入
db.集合名称.insertMany([])
>db.shop.insert({name:"华为",price:6666})
>db.shop.insertOne({name:"伏地魔"})
>db.shop.save({name:"马士兵教育"})
>db.shop.insertMany([{name:"华为",price:1111},{name:"小米",price:2222}])
查询
db.集合名称.find(query,[projection])
query :可选,查询筛选器 JSON 对象
projection:可选,结果字段 JSON 对象
>db.shop.find().pretty() #查询全部
>db.shop.find({name:"华为"}) #带条件查询
>var c = db.shop.find() #得到游标
>while(c.hasNext()){print(tojson(c.next()));} #游标迭代
>db.shop.find().limit(2).forEach(printjson) #limit()个数限制,forEach()迭代
>db.shop.find().sort({age:-1}) #sort()排序 按照age字段排序 -1表示降序,1表示升序
删除
db.集合名称.remove({})
>db.shop.remove({}) # 删除所有
>db.shop.remove({name:"伏地魔"}) # name是伏地魔的
>db.shop.remove({price:{$lte:2000}}) # price小于等于2000的
更新
db.集合名称.update(query,update)
db.集合名称.updateOne(query,update)
db.集合名称.updateMany(query,update)
query:条件,JSON对象
update: 更新字段 JSON对象
>db.shop.update({name:"小米"},{$set:{price:3333}})
>db.shop.updateOne({y:111},{$set:{price:3333}})
>db.shop.updateMany({price:3333},{$set:{age:18}})
聚合
相当于 SQL 查询的 GROUP BY,LEFT JOIN等操作
db.集合名称.count()
db.集合名称.distinct(Field) – Field字段名称必须
>db.shop.count() #统计文档数量
>db.shop.distinct("price") #字段去重并返回去重后的值(数组)
关系 | 格式 | 例子 |
---|---|---|
等于 | {< key > : < value >} | db.shop.find({name:“小米”}).pretty() |
小于 | {< key > : {$lt : < value >}} | db.shop.find({price:{$lt:100}}).pretty() |
小于等于 | {< key > : {$lte : < value >}} | db.shop.find({price:{$lte:100}}).pretty() |
大于 | {< key > : {$gt : < value >}} | db.shop.find({price:{$gt:100}}).pretty() |
大于等于 | {< key > : {$gte : < value >}} | db.shop.find({price:{$gte:100}}).pretty() |
不等于 | {< key > : {$ne : < value >}} | db.shop.find({price:{$ne:100}}).pretty() |
and | {key1:value1,key2:value2} {$and:[{key1:value1},{key2:value2}]} |
db.shop.find({name:“小米”,price:100}).pretty() db.shop.find({$and:[{name:“小米”},{price:100}]}).pretty() |
or | {$or:[{key1:value1},{key2:value2}]} | db.shop.find({$or:[{name:“小米”},{price:100}]}).pretty() |
and or 联合 | {key1:{KaTeX parse error: Expected 'EOF', got '}' at position 13: lte : value1}̲,or:[{key2 : value2},{key3 : value3}]} | db.shop.find({price:{KaTeX parse error: Expected 'EOF', got '}' at position 8: lte:100}̲,or:[{name:“小米”},{name:“z”}]}).pretty() |
$type | {key1 : {$type :‘string’}} | db.shop.find({addr:{$type:‘string’}}).pretty() |
$set 更新或添加字段 | {$set : {key : value}} | db.shop.update({name:“zzz”},{$set:{email:111}}) |
$unset 删除字段 | {$unset : {key : 1}} | db.shop.update({name:“zzz”},{$unset:{email:1}}) |
$inc 数字增减 | {$inc : {key:value}} | db.shop.update({name:“zzz”},{$inc:{price:10}}) |
$pull 数组删除元素 | {$pull : {key : value }} | db.shop.update({name:“zzz”},{$pull:{addr:“xx”}}) |
$pop 删除数组firts/last | {$pop : {key : -1/1}} | db.shop.update({name:“zzz”},{$pop:{addr:-1}}) |
$rename 修改字段名称 | {$rename : {oldName : newName}} | db.shop.update({name:“zzz”},{$rename:{addr : address}}) |
$bit 位操作 integer类型 | {$bit : {and/or : 5}} | db.shop.insert({name:“qqq”,bits: NumberInt(2)}) db.shop.update({name:“qqq”},{$bit : {bits: {or: NumberInt(1)}}}) |
用途 | 方法 | 例子 |
---|---|---|
分页查询 | limit(n) | db.shop.find().limit(2).pretty() |
跳越查询 | skip(n) | db.shop.find().skip(2).pretty() |
排序(1:升序 -1:降序) | sort({key1:1/-1}) | db.shop.find({},{name:1,_id:0,price:1}).sort({price:-1}).pretty() |
统计 | count() | db.shop.count() |
去重 | distinct(key) | db.shop.distinct(“name”) |
表达式 | 功能 | 例子 |
---|---|---|
$sum | 求和 | db.shop.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"name",num_price:{ s u m : " sum:" sum:"price"}}}]) |
$avg | 求平均值 | db.shop.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"name",num_price:{ a v g : " avg:" avg:"price"}}}]) |
$min | 最小值 | db.shop.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"name",num_price:{ m i n : " min:" min:"price"}}}]) |
$max | 最大值 | db.shop.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"name",num_price:{ m a x : " max:" max:"price"}}}]) |
$push | 结果文档中插入值到一个数组中 | db.shop.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"name",price:{ p u s h : " push:" push:"price"}}}]) |
$addToSet | 结果文档中插入值到一个数组中,但不创建副本 | db.shop.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"name",price:{ a d d T o S e t : " addToSet:" addToSet:"price"}}}]) |
$first | 获取第一个文档数据 | db.shop.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"name",price:{ f i r s t : " first:" first:"price"}}}]) |
$last | 获取最后一个文档数据 | db.shop.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"name",price:{ l a s t : " last:" last:"price"}}}]) |
表达式 | 功能 | 例子 |
---|---|---|
$project | 修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档 | db.shop.aggregate({$project : {name: 1,price:1,_id:0}}) |
$match | 用于过滤数据,只输出符合条件的文档 | db.shop.aggregate([{$match:{name:“zzz”}}]) |
$limit | 用来限制MongoDB聚合管道返回的文档数 | db.shop.aggregate({$limit: 2}) |
$skip | 跳过指定数量的文档,并返回余下的文档 | db.shop.aggregate({$skip: 5}) |
$unwind | 将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值 addrs是数组 | db.shop.aggregate([{ u n w i n d : " unwind:" unwind:"addrs"}]) |
$group | 将集合中的文档分组,可用于统计结果 | db.shop.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"name"}}]) |
$sort | 将输入文档排序后输出 | db.shop.aggregate([{$sort:{price:-1}}]) |
$geoNear | 输出接近某一地理位置的有序文档 | ## |
备份
# 导出当前机器上的 test 库到当前位置
./mongodump -h localhost:27017 -uroot -p123456 --authenticationDatabase=admin -d test -o .
-h:
MongoDB 所在服务器地址,例如:127.0.0.1,当然也可以指定端口号:127.0.0.1:27017
-d:
需要备份的数据库实例,例如:test
-o:
备份的数据存放位置,例如:c:\data\dump,当然该目录需要提前建立,在备份完成后,系统自动在dump目录下建立一个test目录,这个目录里面存放该数据库实例的备份数据。
恢复
#导入/shadow目录下的库
./mongorestore -h localhost:27017 -d shadow -dir ./shadow/
–host <:port>, -h <:port>:
MongoDB所在服务器地址,默认为: localhost:27017
–db , -d :
需要恢复的数据库实例,例如:test,当然这个名称也可以和备份时候的不一样,比如test2
–drop:
恢复的时候,先删除当前数据,然后恢复备份的数据。就是说,恢复后,备份后添加修改的数据都会被删除,慎用哦!
< path >:
mongorestore 最后的一个参数,设置备份数据所在位置,例如:c:\data\dump\test。
你不能同时指定 和 --dir 选项,–dir也可以设置备份目录。
–dir:
指定备份的目录
你不能同时指定 < path > 和 --dir 选项。
mongostat
./bin/mongostat -h localhost -p 27017 -uroot -p123456 --authenticationDatabase=admin
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cHy2BjHx-1624682480478)(./mongostat.jpg)]
mongotop
./bin/mongotop -h localhost -p 27017 -uroot -p123456 --authenticationDatabase=admin 10
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sXsdLcdt-1624682480480)(./mongotop.jpg)]
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>2.3.1.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-mongodbartifactId>
<version>2.3.1.RELEASEversion>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.70version>
dependency>
<dependency>
<groupId>org.mongodbgroupId>
<artifactId>mongodb-driver-coreartifactId>
<version>4.0.4version>
dependency>
<dependency>
<groupId>org.mongodbgroupId>
<artifactId>mongodb-driver-syncartifactId>
<version>4.0.4version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
server:
port: 8888
spring:
data:
mongodb:
# 连接 admin 库
uri: mongodb://root:[email protected]:27017/admin
# 需要用户名和密码认证
#uri: mongodb://username:password@ip:port/admin
#不需要用户名和密码认证
#uri: mongodb://ip:port/admin
logging:
level:
org:
springframework:
data:
mongodb: DEBUG
User.java
@Data
@Accessors(chain = true)
@Document("users") // 集合名称 users
public class User {
private String name;
private int age;
private List<Address> addresses;
private List<String> emails;
private Map<String,String> phones;
}
Address.java
@Data
@Accessors(chain = true)
public class Address {
private String province;
private String city;
private String town;
}
UserService.java
public interface UserService {
User insert(User user);
long update(String uname);
long updateChild(String uname,int index,String email);
long delete(String uname);
List<User> list();
List<User> list(String uname);
List<User> find(String province);
}
UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private MongoTemplate mongoTemplate;
@Override
public User insert(User user) {
// 添加记录
return mongoTemplate.insert(user);
}
@Override
public long update(String uname) {
Query query = new Query();
query.addCriteria(Criteria.where("name").is(uname).and("addresses.province").is("新疆"));
// .$ 更新查询出的数组中的元素字段值,并设置新字段 street、ss(数组)
Update update = Update.update("addresses.$.province", "武汉") // child 属性
.set("age",30)
.set("addresses.$.street","Thanks♪(・ω・)ノ街道")
.addToSet("addresses.$.ss", Arrays.asList("q","w","e"));
UpdateResult result = mongoTemplate.updateMulti(query, update, User.class);
return result.getModifiedCount();
}
@Override
public long updateChild(String uname,int index,String email) {
Query query = new Query();
query.addCriteria(Criteria.where("name").is(uname));
Update update = Update.update("emails." + index, email); // .index 指定数组下标更新
UpdateResult result = mongoTemplate.updateMulti(query, update, User.class);
return result.getModifiedCount();
}
@Override
public long delete(String uname) {
Query query = new Query();
query.addCriteria(Criteria.where("name").is(uname));
DeleteResult result = mongoTemplate.remove(query,User.class);
return result.getDeletedCount();
}
@Override
public List<User> list() {
Query query = new Query();
return mongoTemplate.find(query, User.class);
}
@Override
public List<User> list(String uname) {
Query query = new Query();
query.addCriteria(Criteria.where("name").is(uname));
return mongoTemplate.find(query, User.class);
}
@Override
public List<User> find(String province) {
Query query = new Query();
query.addCriteria(Criteria.where("addresses.0.province").is(province));
return mongoTemplate.find(query,User.class);
}
}
UserController.java
@RestController
@RequestMapping("/mongo")
public class UserController {
@Autowired
private UserService userService;
/**
* 添加文档
*{
* "name":"shadow",
* "age":18,
* "addresses":[
* {
* "province":"湖南",
* "city":"张家界",
* "town":"永定区"
* },
* {
* "province":"广东",
* "city":"深圳",
* "town":"龙华区"
* }
* ],
* "emails":["[email protected]","[email protected]"],
* "phones":{
* "1":"110",
* "2":"119",
* "3":"114"* }
* }
*/
@PostMapping("/insert")
public User insert(@RequestBody User user) {
return userService.insert(user);
}
/**
* 更新文档
* /mongo/update/shadow
*/
@PutMapping("/update/{uname}")
public long update(@PathVariable("uname")String uname) {
return userService.update(uname);
}
/**
* 更新文档子内容
* /mongo/update/child/shadow/[email protected]
*/
@PutMapping("/update/child/{uname}/{index}/{email}")
public long updateChild(@PathVariable("uname")String uname,@PathVariable("index")int index,@PathVariable("email")String email) {
return userService.updateChild(uname,index,email);
}
/**
* 删除文档
* /mongo/delete/shadow
*/
@DeleteMapping("/delete/{uname}")
public long delete(@PathVariable("uname")String uname) {
return userService.delete(uname);
}
/**
* 查询文档
* /mongo/list
*/
@GetMapping("/list")
public List<User> list() {
return userService.list();
}
/**
* 条件查询
* /mongo/find/condition/shadow
*/
@GetMapping("/find/condition/{uname}")
public List<User> list(@PathVariable("uname")String uname) {
return userService.list(uname);
}
/**
* 内部条件查询
* /mongo/find/inner/condition?province=湖南
*/
@GetMapping("/find/inner/condition")
public List<User> find(@RequestParam("province")String province) {
return userService.find(province);
}
}
postman.json
{
"id": "87c81fb4-d538-0608-7bf1-b2a2b286ffb1",
"name": "mongoDB",
"description": "",
"order": [
"907d983b-80a1-54a8-a4e5-429b58337ef5",
"ae8480f4-7d84-438a-96d3-e0886d62ceca",
"422eefa1-ddb3-16ae-9f6d-64fba2c35738",
"32107e4b-4476-9833-bf6c-331b45fcd855",
"736dd113-f406-b66a-fae8-9042a073297f",
"31f6a2d3-c359-b239-c942-f96cd42e3a0e",
"902c88af-9d54-771d-b051-114a2fd9560b"
],
"folders": [],
"folders_order": [],
"timestamp": 1618284064028,
"owner": 0,
"public": false,
"requests": [
{
"id": "31f6a2d3-c359-b239-c942-f96cd42e3a0e",
"headers": "",
"headerData": [],
"url": "localhost:8888/mongo/find/condition/shadow1",
"queryParams": [],
"pathVariables": {},
"pathVariableData": [],
"preRequestScript": null,
"method": "GET",
"collectionId": "87c81fb4-d538-0608-7bf1-b2a2b286ffb1",
"data": null,
"dataMode": "params",
"name": "查询文档-带条件",
"description": "",
"descriptionFormat": "html",
"time": 1618297217476,
"version": 2,
"responses": [],
"tests": null,
"currentHelper": "normal",
"helperAttributes": {}
},
{
"id": "32107e4b-4476-9833-bf6c-331b45fcd855",
"headers": "",
"headerData": [],
"url": "localhost:8888/mongo/delete/shadow",
"queryParams": [],
"pathVariables": {},
"pathVariableData": [],
"preRequestScript": null,
"method": "DELETE",
"collectionId": "87c81fb4-d538-0608-7bf1-b2a2b286ffb1",
"data": null,
"dataMode": "params",
"name": "删除文档",
"description": "",
"descriptionFormat": "html",
"time": 1618296656680,
"version": 2,
"responses": [],
"tests": null,
"currentHelper": "normal",
"helperAttributes": {}
},
{
"id": "422eefa1-ddb3-16ae-9f6d-64fba2c35738",
"headers": "",
"headerData": [],
"url": "localhost:8888/mongo/update/child/shadow/0/[email protected]",
"queryParams": [],
"pathVariables": {},
"pathVariableData": [],
"preRequestScript": null,
"method": "PUT",
"collectionId": "87c81fb4-d538-0608-7bf1-b2a2b286ffb1",
"data": null,
"dataMode": "params",
"name": "指定条件及数组下标更新文档",
"description": "",
"descriptionFormat": "html",
"time": 1618295075331,
"version": 2,
"responses": [],
"tests": null,
"currentHelper": "normal",
"helperAttributes": {}
},
{
"id": "736dd113-f406-b66a-fae8-9042a073297f",
"headers": "",
"headerData": [],
"url": "localhost:8888/mongo/list",
"queryParams": [],
"pathVariables": {},
"pathVariableData": [],
"preRequestScript": null,
"method": "GET",
"collectionId": "87c81fb4-d538-0608-7bf1-b2a2b286ffb1",
"data": null,
"dataMode": "params",
"name": "查询全部文档",
"description": "",
"descriptionFormat": "html",
"time": 1618296896751,
"version": 2,
"responses": [],
"tests": null,
"currentHelper": "normal",
"helperAttributes": {}
},
{
"id": "902c88af-9d54-771d-b051-114a2fd9560b",
"headers": "",
"headerData": [],
"url": "localhost:8888/mongo/find/inner/condition?province=湖南",
"queryParams": [
{
"key": "province",
"value": "湖南",
"equals": true,
"description": "",
"enabled": true
}
],
"pathVariables": {},
"pathVariableData": [],
"preRequestScript": null,
"method": "GET",
"collectionId": "87c81fb4-d538-0608-7bf1-b2a2b286ffb1",
"data": null,
"dataMode": "params",
"name": "查询文档-带内部条件",
"description": "",
"descriptionFormat": "html",
"time": 1618298214423,
"version": 2,
"responses": [],
"tests": null,
"currentHelper": "normal",
"helperAttributes": {}
},
{
"id": "907d983b-80a1-54a8-a4e5-429b58337ef5",
"headers": "Content-Type: application/json\n",
"headerData": [
{
"key": "Content-Type",
"value": "application/json",
"description": "",
"enabled": true
}
],
"url": "localhost:8888/mongo/insert",
"queryParams": [],
"preRequestScript": null,
"pathVariables": {},
"pathVariableData": [],
"method": "POST",
"data": [],
"dataMode": "raw",
"tests": null,
"currentHelper": "normal",
"helperAttributes": {},
"time": 1618297220124,
"name": "添加文档",
"description": "",
"collectionId": "87c81fb4-d538-0608-7bf1-b2a2b286ffb1",
"responses": [],
"rawModeData": "{\n\t\"name\":\"shadow1\",\n\t\"age\":18,\n\t\"addresses\":[\n\t\t{\n\t\t\t\"province\":\"湖南\",\n\t\t\t\"city\":\"张家界\",\n\t\t\t\"town\":\"永定区\"\n\t\t},\n\t\t{\n\t\t\t\"province\":\"广东\",\n\t\t\t\"city\":\"深圳\",\n\t\t\t\"town\":\"龙华区\"\n\t\t}\n\t\t],\n\t\"emails\":[\"[email protected]\",\"[email protected]\"],\n\t\"phones\":{\n\t\t\"1\":\"110\",\n\t\t\"2\":\"119\",\n\t\t\"3\":\"114\"\n\t}\n}"
},
{
"id": "ae8480f4-7d84-438a-96d3-e0886d62ceca",
"headers": "",
"headerData": [],
"url": "localhost:8888/mongo/update/shadow",
"queryParams": [],
"pathVariables": {},
"pathVariableData": [],
"preRequestScript": null,
"method": "PUT",
"collectionId": "87c81fb4-d538-0608-7bf1-b2a2b286ffb1",
"data": null,
"dataMode": "params",
"name": "更新文档",
"description": "",
"descriptionFormat": "html",
"time": 1618291236895,
"version": 2,
"responses": [],
"tests": null,
"currentHelper": "normal",
"helperAttributes": {}
}
]
}
MongoDB中的副本集是一组维护相同数据集的mongod进程。复制集提供冗余和高可用性,是所有生产部署的基础
Oplog(operations log)是一个特殊的集合,记录所有的对于修改数据库(新增,修改,删除)的行为日志,这些日志,被称为Oplog
两种数据同步方式:
① 初始同步 :复制全量的数据从副本集当中的另一个成员哪里
② 复制 :从节点在初始同步后连续复制数据
选举机制:从节点在初始同步后连续复制数据
具有投票权的节点之间两两互相发送心跳 当5次心跳未收到时判断为节点失联 如果主节点失联,从节点会发起选举,选出新的主节点 如果从节点失联,不发生新的选举 选举算法:RAFT一致性算法。成功的必要条件是大多数投票节点存活 副本集中最多可以有50个节点,但具有投票权的节点最多7个
副本集特征:
- N 个节点的集群
- 任何节点可作为主节点
- 所有写入操作都在主节点上
- 自动故障转移
- 自动恢复
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YtM6Yb1d-1624682480483)(./replication.png)]
主机规划
ip | port | role |
---|---|---|
10.25.175.108 | 28017 | primary |
10.25.175.108 | 28018 | secondary |
10.25.175.108 | 28019 | secondary |
下载安装包
解压安装包
tar -zxvf mongodb-linux-x86_64-rhel62-4.0.23.tgz
拷贝三份到17/18/19文件夹中
cp -r mongodb-linux-x86_64-rhel62-4.0.23 mongo17
cp -r mongodb-linux-x86_64-rhel62-4.0.23 mongo18
cp -r mongodb-linux-x86_64-rhel62-4.0.23 mongo19
在17/18/19文件夹中创建三个目录
cd mongo17/
mkdir data
mkdir logs
mkdir conf
cd ../mongo18/
mkdir data
mkdir logs
mkdir conf
cd ../mongo19/
mkdir data
mkdir logs
mkdir conf
创建 log 文件
touch mongo.log
cp mongo.log ./mongo17/logs/
cp mongo.log ./mongo18/logs/
cp mongo.log ./mongo19/logs/
rm -rf mongo.log
创建配置文件并配置
touch mongod.conf
cp mongod.conf ./mongo17/conf/
cp mongod.conf ./mongo18/conf/
cp mongod.conf ./mongo19/conf/
rm -rf mongod.conf
主节点 - 17
vim ./mongo17/conf/mongod.conf
systemLog:
destination: file
path: "/xx/xxx/mongodb/mongo17/logs/mongo.log"
logAppend: true
storage:
dbPath: "/xx/xxx/mongodb/mongo17/data"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/xx/xxx/mongodb/mongo17/logs/mongod.pid"
net:
bindIp: 0.0.0.0
port: 28017
replication:
replSetName: rs0
从节点01 - 18
vim ./mongo18/conf/mongod.conf
systemLog:
destination: file
path: "/xx/xxx/mongodb/mongo18/logs/mongo.log"
logAppend: true
storage:
dbPath: "/xx/xxx/mongodb/mongo18/data"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/xx/xxx/mongodb/mongo18/logs/mongod.pid"
net:
bindIp: 0.0.0.0
port: 28018
replication:
replSetName: rs0
从节点02 - 19
vim ./mongo19/conf/mongod.conf
systemLog:
destination: file
path: "/xx/xxx/mongodb/mongo19/logs/mongo.log"
logAppend: true
storage:
dbPath: "/xx/xxx/mongodb/mongo19/data"
journal:
enabled: true
processManagement:
fork: true
pidFilePath: "/xx/xxx/mongodb/mongo19/logs/mongod.pid"
net:
bindIp: 0.0.0.0
port: 28019
replication:
replSetName: rs0
启动服务
./mongo17/bin/mongod -f ./mongo17/conf/mongod.conf
./mongo18/bin/mongod -f ./mongo18/conf/mongod.conf
./mongo19/bin/mongod -f ./mongo19/conf/mongod.conf
连接服务
./mongo17/bin/mongo --prot 28017
初始化副本集(_id 的值 rs0 必须和配置文件中的replication.replSetName保持一致)
>use admin
>rs.initiate({
_id:"rs0",
members:[
{_id:0,host:"10.25.175.108:28017",priority:1},
{_id:1,host:"10.25.175.108:28018",priority:1},
{_id:2,host:"10.25.175.108:28019",priority:1}
]
})
>rs.status()
>use shadow #切换到shadow库
>db.user.insert({name:"shadow"}) #创建user集合并存储文档
>db.user.find()
连接其他服务,可看见主从情况
./mongo18/bin/mongo --port 28018
./mongo19/bin/mongo --port 28019
分别执行以下命令
>db.getMongo().setSecondaryOk() #设置副本节点可以读 或者 rs.salveOk()
>use shadow #切换到shadow库
>db.user.find() #查询user集合中的文档
Compass连接
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hg2aGXTe-1624682480486)(./rs.jpg)]
操作手册
初始化副本集
rs.initiate({
_id:"rs0", #这里和配置文件必须保持一致
members:[
{_id:0,host:"10.25.175.108:28017",priority:1},
{_id:1,host:"10.25.175.108:28018",priority:1},
{_id:2,host:"10.25.175.108:28019",priority:1}
]
})
添加副本集
rs.add({_id:3,host:"10.25.175.108:28020",priority:1})
#添加仲裁节点 rs.addArb(_id:3,host:"10.25.175.108:28020")
移除副本集
rs.remove("10.25.175.108:28018")
查看副本集配置
rs.conf()
修改副本集配置
conf = rs.conf()
conf.members[0].priority=2
rs.reconfig(conf)
查看副本集状态
rs.status()
原子性(A):事务是最小单位,不可再分(更多关注多行)
一致性©:事务要求所有的DML语句操作的时候,必须保证同时成功或者同时失败
隔离性(I):事务A和事务B之间具有隔离性
持久性(D):是事务的保证,事务终结的标志(内存的数据持久到硬盘文件中)
写事务
writeConcern:
写关注描述了一次写请求的确认级别,写:包括 向独立的mongod进程,副本集或分片集群
{ w: <, j: <, wtimeout: < }w:决定一个写操作落到多少个节点上才算成功,值包括:
0:发起写操作,不关心是否成功
1~集群最大数据节点数: 写操作数据需要全部复制到配置节点上才算成功
majority:数据需要被复制到大多数节点上才算成功
默认:0
>conf = rs.conf()
>conf.members[1].priority=0 #优先级
>conf.members[1].slaveDelay=10 #延迟10s同步
>rs.reconfig(conf) #重新加载配置
>rs.conf() #查看配置情况
>db.shop.insert({name:"x"}) #马上返回,执行成功
>db.shop.insert({name:"x"},{writeConcern:{w:1}}) #马上返回,执行成功
>db.shop.insert({name:"x"},{writeConcern:{w:2}}) #马上返回,执行成功
>db.shop.insert({name:"x"},{writeConcern:{w:3}}) #等待10s返回,执行成功
>db.shop.insert({name:"x"},{writeConcern:{w:"majority"}}) #马上返回,执行成功
>db.shop.insert({name:"x"},{writeConcern:{w:4}}) #警告,没有足够的数据节点,执行成功
读事务
有别于传统的关系型数据库,mongo天生就是分布式数据库,所以mongo读取数据的时候更关注以下两点:
1、从哪里读?关注数据节点的位置 - 由 readPreference 解决
2、什么样的数据可以读?关注数据的隔离性 - 由 readConcern 解决
readPreference 决定读取的数据来自那个数据节点,可选值:
primary: 只读取主节点
primaryPreferred: 优先读取主节点,如果不可用则选择从节点
secondary:只选择从节点
secondaryPreferred: 优先读取从节点,如果从节点不可用则选择主节点
nearest: 选择最近的节点
默认:primary
readConcern 决定这个节点上的数据那些是可读取的,类似关系数据库的隔离级别。可选值包括:
- availavle: 读取所有可用的数据
- local: 读取所有可用且数据当前分片的数据
- majority: 读取在大多数节点上提交完成的数据
- linearizable: 线性化读取文档
- snapshot: 读取最近快照中心的数据
- 默认:local
事务操作
>s = db.getMongo().startSession()
>s.startTransaction() #开启事务
>s.getDatabase("shadow").shop.insert({name:"wq"})
>s.getDatabase("shadow").user.insert({age:10})
>s.commitTransaction() # 提交或者回滚 s.abortTransaction()
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>2.3.1.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-mongodbartifactId>
<version>2.3.1.RELEASEversion>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.70version>
dependency>
<dependency>
<groupId>org.mongodbgroupId>
<artifactId>mongodb-driver-coreartifactId>
<version>4.0.4version>
dependency>
<dependency>
<groupId>org.mongodbgroupId>
<artifactId>mongodb-driver-syncartifactId>
<version>4.0.4version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
server:
port: 8888
spring:
data:
mongodb:
uri: mongodb://10.25.175.108:28017,10.25.175.108:28018,10.25.175.108:28019/shadow?connect=replicaSet&slaveOk=true&replicaSet=rs0&readPreference=secondary
logging:
level:
org:
springframework:
data:
mongodb: debug
TransactionConfig.java
@Configuration
public class TransactionConfig {
@Bean
MongoTransactionManager transactionManager(MongoDatabaseFactory factory){
return new MongoTransactionManager(factory);
}
}
Apple.java
@Data
@AllArgsConstructor
@Document("apples") // 集合名称 apples,需要先创建好
public class Apple {
private String color;
private Integer price;
}
Fruit.java
@Data
@AllArgsConstructor
@Document("fruits") // 集合名称 fruits,需要先创建好
public class Fruit {
private String color;
private String name;
}
BusinessService.java
public interface BusinessService {
String insert();
}
BusinessServiceImpl.java
@Service
public class BusinessServiceImpl implements BusinessService {
@Autowired
private MongoTemplate mongoTemplate;
@Transactional
public String insert() {
Apple apple = new Apple("红色", 10);
Fruit fruit = new Fruit("黄色", "香蕉");
Apple apple1 = mongoTemplate.insert(apple);
Fruit fruit1 = mongoTemplate.insert(fruit);
// System.out.println(1 / 0);
return apple1 + " | " + fruit1;
}
}
MongoTransactionController.java
@RestController
@RequestMapping("/mongo")
public class MongoTransactionController {
@Autowired
private BusinessService businessService;
/**
* 执行 Mongo 事务
*/
@GetMapping("/transaction/insert")
public String insert() {
return businessService.insert();
}
}
发送请求
curl "localhost:8888/mongo/transaction/insert"
查看 mongodb 数据库存储信息
# 连接 mongo 集群中的一台服务
./bin/mongo --port 28017
>use shadow
>show collections
>db.apples.find()
>db.fruits.find()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hUugMF0F-1624682480487)(./res.jpg)]
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构
创建索引语法
语法中 Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可
db.集合名称.createIndex(keys,options)
或者
db.集合名称.ensureIndex(keys,options)
options:
参数 类型 描述 background boolean 是否后台创建索引 unique boolean 是否唯一索引 name string 索引名称 expireAfterSeconds integer TTL 过期时间
案例
db.shop.createIndex({price:1,name:-1},{background: true,expireAfterSeconds:10})
其他操作
操作 | 描述 | 例子 |
---|---|---|
db.集合名称.getIndexes() | 查看集合索引 | db.shop.getIndexes() |
db.集合名称.totalIndexSize() | 查看集合索引大小 | db.shop.totalIndexSize() |
db.集合名称.dropIndexes() | 删除集合所有索引 | db.shop.dropIndexes() |
db.集合名称.dropIndex(“索引名称”) | 删除集合指定索引 | db.shop.dropIndex(“idx_name”) |
查看查询语句是否使用了索引 explain()
db.集合名称.find({}).explain(verbose)
verbose:
- queryPlanner 默认
- executionStats
- allPlansExecution
>db.shop.find({name:"zzz",price:{$lte:100}}).explain("allPlansExecution")
强制使用指定索引 hint()
>db.shop.createIndex({name:1,price:1},{background:true}) #创建索引
>db.shop.find({name:"zzz"},{_id:0,name:1}).hint({name:1,price:1}).explain()#强制使用索引
索引限制
分片角色
角色 | 作用 |
---|---|
Config Server | 配置服务 |
Shard(replica set) | 分片服务(副本集) |
Router(mongos) | 路由服务 |
主机规划
ip | port | role |
---|---|---|
10.25.175.108 | 28001 | Config Server-1 |
10.25.175.108 | 28002 | Config Server-2 |
10.25.175.108 | 28003 | Config Server-3 |
10.25.175.108 | 28011 | Router-1 |
10.25.175.108 | 28012 | Router-2 |
10.25.175.108 | 28013 | Router-3 |
10.25.175.108 | 28021 | Shard-1-primary |
10.25.175.108 | 28022 | Shard-1-secondary |
10.25.175.108 | 28023 | Shard-1-secondary |
10.25.175.108 | 28031 | Shadr-2-primary |
10.25.175.108 | 28032 | Shard-2-secondary |
10.25.175.108 | 28033 | Shard-2-secondary |
10.25.175.108 | 28041 | Shard-3-primary |
10.25.175.108 | 28042 | Shard-3-secondary |
10.25.175.108 | 28043 | Shard-3-secondary |
下载安装包
解压安装包
tar -zxvf mongodb-linux-x86_64-rhel62-4.0.23.tgz
重命名并创建文件夹
mv mongodb-linux-x86_64-rhel62-4.0.23 mongo
mkdir ./mongo/data
mkdir ./mongo/conf
mkdir ./mongo/logs
touch mongod.conf
cp mongod.conf ./mongo/conf/
rm -rf mongod.conf
touch mongo.log
cp mongo.log ./mongo/logs/
rm -rf mongo.log
创建目录
# configServer
mkdir -p configServer/cfServer28001
mkdir -p configServer/cfServer28002
mkdir -p configServer/cfServer28003
# routerServer
mkdir -p routerServer/rServer28011
mkdir -p routerServer/rServer28012
mkdir -p routerServer/rServer28013
# shard-1
mkdir -p shardServer/shard01/sServer28021
mkdir -p shardServer/shard01/sServer28022
mkdir -p shardServer/shard01/sServer28023
# shard-2
mkdir -p shardServer/shard02/sServer28031
mkdir -p shardServer/shard02/sServer28032
mkdir -p shardServer/shard02/sServer28033
# shard-3
mkdir -p shardServer/shard03/sServer28041
mkdir -p shardServer/shard03/sServer28042
mkdir -p shardServer/shard03/sServer28043
拷贝文件
# configServer
cp -r mongo ./configServer/cfServer28001/
cp -r mongo ./configServer/cfServer28002/
cp -r mongo ./configServer/cfServer28003/
# routerServer
cp -r mongo ./routerServer/rServer28011/
cp -r mongo ./routerServer/rServer28012/
cp -r mongo ./routerServer/rServer28013/
# shard-1
cp -r mongo ./shardServer/shard01/sServer28021
cp -r mongo ./shardServer/shard01/sServer28022
cp -r mongo ./shardServer/shard01/sServer28023
# shard-2
cp -r mongo ./shardServer/shard02/sServer28031
cp -r mongo ./shardServer/shard02/sServer28032
cp -r mongo ./shardServer/shard02/sServer28033
# shard-3
cp -r mongo ./shardServer/shard03/sServer28041
cp -r mongo ./shardServer/shard03/sServer28042
cp -r mongo ./shardServer/shard03/sServer28043
查看目录结构
tree -d ./configServer
tree -d ./routerServer
tree -d ./shardServer
配置 configServer
cfServer28001 配置
# 28001
cd configServer/cfServer28001/mongo/conf
vim mongod.conf
配置以下内容
pidfilepath = /xx/xxx/mongodb/configServer/cfServer28001/mongo/logs/configsrv.pid
dbpath = /xx/xxx/mongodb/configServer/cfServer28001/mongo/data
logpath = /xx/xxx/mongodb/configServer/cfServer28001/mongo/logs/mongo.log
logappend = true
bind_ip = 0.0.0.0
port = 28001
fork = true
#declare this is a config db of a cluster;
configsvr = true
#副本集名称
replSet=rss
#设置最大连接数
maxConns=20000
cfServer28002 配置
# 28002
cd configServer/cfServer28002/mongo/conf
vim mongod.conf
配置以下内容
pidfilepath = /xx/xxx/mongodb/configServer/cfServer28002/mongo/logs/configsrv.pid
dbpath = /xx/xxx/mongodb/configServer/cfServer28002/mongo/data
logpath = /xx/xxx/mongodb/configServer/cfServer28002/mongo/logs/mongo.log
logappend = true
bind_ip = 0.0.0.0
port = 28002
fork = true
#declare this is a config db of a cluster;
configsvr = true
#副本集名称
replSet=rss
#设置最大连接数
maxConns=20000
cfServer28003 配置
# 28003
cd configServer/cfServer28003/mongo/conf
vim mongod.conf
配置以下内容
pidfilepath = /xx/xxx/mongodb/configServer/cfServer28003/mongo/logs/configsrv.pid
dbpath = /xx/xxx/mongodb/configServer/cfServer28003/mongo/data
logpath = /xx/xxx/mongodb/configServer/cfServer28003/mongo/logs/mongo.log
logappend = true
bind_ip = 0.0.0.0
port = 28003
fork = true
#declare this is a config db of a cluster;
configsvr = true
#副本集名称
replSet=rss
#设置最大连接数
maxConns=20000
启动 三台 configServer
./cfServer28001/mongo/bin/mongod -f ./cfServer28001/mongo/conf/mongod.conf
./cfServer28002/mongo/bin/mongod -f ./cfServer28002/mongo/conf/mongod.conf
./cfServer28003/mongo/bin/mongod -f ./cfServer28003/mongo/conf/mongod.conf
连接 configServer 并初始化集群
./cfServer28001/mongo/bin/mongo --port 28001
>use admin
>rs.initiate({
_id:"rss",
members:[
{_id:0,host:"10.25.175.108:28001"},
{_id:1,host:"10.25.175.108:28002"},
{_id:2,host:"10.25.175.108:28003"}
]
})
配置分片集群
配置 shard-1
shard01-28021 配置
# 28021
cd shardServer/shard01/sServer28021/mongo/conf
vim mongod.conf
配置以下内容
pidfilepath = /xx/xxx/mongodb/shardServer/shard01/sServer28021/mongo/logs/shard1.pid
dbpath = /xx/xxx/mongodb/shardServer/shard01/sServer28021/mongo/data
logpath = /xx/xxx/mongodb/shardServer/shard01/sServer28021/mongo/logs/mongo.log
logappend = true
bind_ip = 0.0.0.0
port = 28021
fork = true
#打开web监控
#httpinterface=true
#rest=true
#副本集名称
replSet=shard1
#declare this is a shard db of a cluster;
shardsvr = true
#设置最大连接数
maxConns=20000
shard01-28022 配置
# 28022
cd shardServer/shard01/sServer28022/mongo/conf
vim mongod.conf
配置以下内容
pidfilepath = /xx/xxx/mongodb/shardServer/shard01/sServer28022/mongo/logs/shard1.pid
dbpath = /xx/xxx/mongodb/shardServer/shard01/sServer28022/mongo/data
logpath = /xx/xxx/mongodb/shardServer/shard01/sServer28022/mongo/logs/mongo.log
logappend = true
bind_ip = 0.0.0.0
port = 28022
fork = true
#打开web监控
#httpinterface=true
#rest=true
#副本集名称
replSet=shard1
#declare this is a shard db of a cluster;
shardsvr = true
#设置最大连接数
maxConns=20000
shard01-28023
# 28023
cd shardServer/shard01/sServer28023/mongo/conf
vim mongod.conf
配置以下内容
pidfilepath = /xx/xxx/mongodb/shardServer/shard01/sServer28023/mongo/logs/shard1.pid
dbpath = /xx/xxx/mongodb/shardServer/shard01/sServer28023/mongo/data
logpath = /xx/xxx/mongodb/shardServer/shard01/sServer28023/mongo/logs/mongo.log
logappend = true
bind_ip = 0.0.0.0
port = 28023
fork = true
#打开web监控
#httpinterface=true
#rest=true
#副本集名称
replSet=shard1
#declare this is a shard db of a cluster;
shardsvr = true
#设置最大连接数
maxConns=20000
启动三台 shard-1 服务
./sServer28021/mongo/bin/mongod -f ./sServer28021/mongo/conf/mongod.conf
./sServer28022/mongo/bin/mongod -f ./sServer28022/mongo/conf/mongod.conf
./sServer28023/mongo/bin/mongod -f ./sServer28023/mongo/conf/mongod.conf
连接 shard-1集群并初始化集群
./sServer28021/mongo/bin/mongo --port 28021
>use admin
>rs.initiate({
_id:"shard1",
members:[
{_id:0,host:"10.25.175.108:28021"},
{_id:1,host:"10.25.175.108:28022"},
{_id:2,host:"10.25.175.108:28023"}
]
})
配置 shard-2
shard02-28031
# 28031
cd shardServer/shard02/sServer28031/mongo/conf
vim mongod.conf
配置以下内容
pidfilepath = /xx/xxx/mongodb/shardServer/shard02/sServer28031/mongo/logs/shard2.pid
dbpath = /xx/xxx/mongodb/shardServer/shard02/sServer28031/mongo/data
logpath = /xx/xxx/mongodb/shardServer/shard02/sServer28031/mongo/logs/mongo.log
logappend = true
bind_ip = 0.0.0.0
port = 28031
fork = true
#打开web监控
#httpinterface=true
#rest=true
#副本集名称
replSet=shard2
#declare this is a shard db of a cluster;
shardsvr = true
#设置最大连接数
maxConns=20000
shard02-28032
# 28032
cd shardServer/shard02/sServer28032/mongo/conf
vim mongod.conf
配置以下内容
pidfilepath = /xx/xxx/mongodb/shardServer/shard02/sServer28032/mongo/logs/shard2.pid
dbpath = /xx/xxx/mongodb/shardServer/shard02/sServer28032/mongo/data
logpath = /xx/xxx/mongodb/shardServer/shard02/sServer28032/mongo/logs/mongo.log
logappend = true
bind_ip = 0.0.0.0
port = 28032
fork = true
#打开web监控
#httpinterface=true
#rest=true
#副本集名称
replSet=shard2
#declare this is a shard db of a cluster;
shardsvr = true
#设置最大连接数
maxConns=20000
shard02-28033
# 28033
cd shardServer/shard02/sServer28033/mongo/conf
vim mongod.conf
配置以下内容
pidfilepath = /xx/xxx/mongodb/shardServer/shard02/sServer28033/mongo/logs/shard2.pid
dbpath = /xx/xxx/mongodb/shardServer/shard02/sServer28033/mongo/data
logpath = /xx/xxx/mongodb/shardServer/shard02/sServer28033/mongo/logs/mongo.log
logappend = true
bind_ip = 0.0.0.0
port = 28033
fork = true
#打开web监控
#httpinterface=true
#rest=true
#副本集名称
replSet=shard2
#declare this is a shard db of a cluster;
shardsvr = true
#设置最大连接数
maxConns=20000
启动三台 shard-2 服务
./sServer28031/mongo/bin/mongod -f ./sServer28031/mongo/conf/mongod.conf
./sServer28032/mongo/bin/mongod -f ./sServer28032/mongo/conf/mongod.conf
./sServer28033/mongo/bin/mongod -f ./sServer28033/mongo/conf/mongod.conf
连接 shard-2 集群并初始化集群
./sServer28031/mongo/bin/mongo --port 28031
>use admin
>rs.initiate({
_id:"shard2",
members:[
{_id:0,host:"10.25.175.108:28031"},
{_id:1,host:"10.25.175.108:28032"},
{_id:2,host:"10.25.175.108:28033"}
]
})
配置 shard-3
shard03-28041
# 28041
cd shardServer/shard03/sServer28041/mongo/conf
vim mongod.conf
配置以下内容
pidfilepath = /wls/wls81/mongodb/shardServer/shard03/sServer28041/mongo/logs/shard3.pid
dbpath = /wls/wls81/mongodb/shardServer/shard03/sServer28041/mongo/data
logpath = /wls/wls81/mongodb/shardServer/shard03/sServer28041/mongo/logs/mongo.log
logappend = true
bind_ip = 0.0.0.0
port = 28041
fork = true
#打开web监控
#httpinterface=true
#rest=true
#副本集名称
replSet=shard3
#declare this is a shard db of a cluster;
shardsvr = true
#设置最大连接数
maxConns=20000
shard03-28042
# 28042
cd shardServer/shard03/sServer28042/mongo/conf
vim mongod.conf
配置以下内容
pidfilepath = /xx/xxx/mongodb/shardServer/shard03/sServer28042/mongo/logs/shard3.pid
dbpath = /xx/xxx/mongodb/shardServer/shard03/sServer28042/mongo/data
logpath = /xx/xxx/mongodb/shardServer/shard03/sServer28042/mongo/logs/mongo.log
logappend = true
bind_ip = 0.0.0.0
port = 28042
fork = true
#打开web监控
###httpinterface=true
###rest=true
###副本集名称
replSet=shard3
###declare this is a shard db of a cluster;
shardsvr = true
###设置最大连接数
maxConns=20000
shard03-28043
# 28043
cd shardServer/shard03/sServer28043/mongo/conf
vim mongod.conf
配置以下内容
pidfilepath = /xx/xxx/mongodb/shardServer/shard03/sServer28043/mongo/logs/shard3.pid
dbpath = /xx/xxx/mongodb/shardServer/shard03/sServer28043/mongo/data
logpath = /xx/xxx/mongodb/shardServer/shard03/sServer28043/mongo/logs/mongo.log
logappend = true
bind_ip = 0.0.0.0
port = 28043
fork = true
#打开web监控
###httpinterface=true
###rest=true
###副本集名称
replSet=shard3
###declare this is a shard db of a cluster;
shardsvr = true
###设置最大连接数
maxConns=20000
启动三台 shard-3 服务
./sServer28041/mongo/bin/mongod -f ./sServer28041/mongo/conf/mongod.conf
./sServer28042/mongo/bin/mongod -f ./sServer28042/mongo/conf/mongod.conf
./sServer28043/mongo/bin/mongod -f ./sServer28043/mongo/conf/mongod.conf
连接 shard-3 集群并初始化集群
./sServer28041/mongo/bin/mongo --port 28041
>use admin
>rs.initiate({
_id:"shard3",
members:[
{_id:0,host:"10.25.175.108:28041"},
{_id:1,host:"10.25.175.108:28042"},
{_id:2,host:"10.25.175.108:28043"}
]
})
配置 router (mongos)
rServer- 28011 配置
# 28011
cd routerServer/rServer28011/mongo/conf/
vim mongod.conf
配置以下内容
pidfilepath = /xx/xxx/mongodb/routerServer/rServer28011/mongo/logs/mongos.pid
logpath = /xx/xxx/mongodb/routerServer/rServer28011/mongo/logs/mongos.log
logappend = true
bind_ip = 0.0.0.0
port = 28011
fork = true
#监听的配置服务器,只能有1个或者3个 rss 为配置服务器的副本集名字
configdb = rss/10.25.175.108:28001,10.25.175.108:28002,10.25.175.108:28003
##设置最大连接数
maxConns=20000
rServer-28012 配置
# 28012
cd routerServer/rServer28012/mongo/conf/
vim mongod.conf
配置以下内容
pidfilepath = /wls/wls81/mongodb/routerServer/rServer28012/mongo/logs/mongos.pid
logpath = /wls/wls81/mongodb/routerServer/rServer28012/mongo/logs/mongos.log
logappend = true
bind_ip = 0.0.0.0
port = 28012
fork = true
#监听的配置服务器,只能有1个或者3个 rss 为配置服务器的副本集名字
configdb = rss/10.25.175.108:28001,10.25.175.108:28002,10.25.175.108:28003
##设置最大连接数
maxConns=20000
rServer-28013 配置
# 28013
cd routerServer/rServer28013/mongo/conf/
vim mongod.conf
配置以下内容
pidfilepath = /wls/wls81/mongodb/routerServer/rServer28013/mongo/logs/mongos.pid
logpath = /wls/wls81/mongodb/routerServer/rServer28013/mongo/logs/mongos.log
logappend = true
bind_ip = 0.0.0.0
port = 28013
fork = true
#监听的配置服务器,只能有1个或者3个 rss 为配置服务器的副本集名字
configdb = rss/10.25.175.108:28001,10.25.175.108:28002,10.25.175.108:28003
##设置最大连接数
maxConns=20000
启动三台 mongos 服务
./rServer28011/mongo/bin/mongos -f ./rServer28011/mongo/conf/mongod.conf
./rServer28012/mongo/bin/mongos -f ./rServer28012/mongo/conf/mongod.conf
./rServer28013/mongo/bin/mongos -f ./rServer28013/mongo/conf/mongod.conf
启用分片
./rServer28011/mongo/bin/mongo --port 28011
mongos>use admin
mongos>sh.addShard("shard1/10.25.175.108:28021,10.25.175.108:28022,10.25.175.108:28023")
mongos>sh.addShard("shard2/10.25.175.108:28031,10.25.175.108:28032,10.25.175.108:28033")
mongos>sh.addShard("shard3/10.25.175.108:28041,10.25.175.108:28042,10.25.175.108:28043")
mongos>sh.status()
测试
./rServer28011/mongo/bin/mongo --port 28011
mongos>use admin
mongos>db.runCommand({enablesharding : "shadow"}) #指定shadow分片生效
mongos>db.runCommand({shardcollection : "shadow.shop",key : {name:"hashed"}}) #指定数据库里需要分片的集合和片键 hash 或 范围 {id:1}
mongos>use shadow
mongos>for(var i = 1;i <= 10000) db.shop.save({id:i,name:"wq"+i})
mongos>db.shop.stats()
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>2.3.1.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-mongodbartifactId>
<version>2.3.1.RELEASEversion>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.70version>
dependency>
<dependency>
<groupId>org.mongodbgroupId>
<artifactId>mongodb-driver-coreartifactId>
<version>4.0.4version>
dependency>
<dependency>
<groupId>org.mongodbgroupId>
<artifactId>mongodb-driver-syncartifactId>
<version>4.0.4version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
server:
port: 8888
spring:
data:
mongodb:
# 连接的是 mongos 的路由服务
uri: mongodb://10.25.175.108:28011,10.25.175.108:28012,10.25.175.108:28013/shadow
logging:
level:
org:
springframework:
data:
mongodb: debug
Shop.java
@Data
@Accessors(chain = true)
@Document(collection = "shop")
public class Shop {
private int id;
private String name;
}
ShopRepositiry.java
// Shop类型,主键 Integer 类型
public interface ShopRepository extends MongoRepository<Shop,Integer> {
}
BusinessService.java
public interface BusinessService {
void insert();
}
BusinessServiceImpl.java
@Service
public class BusinessServiceImpl implements BusinessService {
@Autowired
private ShopRepository shopRepository;
@Autowired
private MongoTemplate mongoTemplate;
public void insert() {
Shop shop;
List<Shop> list = new ArrayList<>();
for (int i = 1; i <= 1000; i++) {
shop = new Shop();
shop.setId(i).setName("shadow" + i);
list.add(shop);
}
shopRepository.saveAll(list);
}
}
MongoShardController.java
@RestController
@RequestMapping("/mongo")
public class MongoShardController {
@Autowired
private BusinessService businessService;
/**
* 分片集群测试
*/
@GetMapping("/shard/insert")
public void insert() {
businessService.insert();
}
}
测试
curl "localhost:8888/mongo/shard/insert"
查看数据分布情况
# 路由服务
./rServer28011/mongo/bin/mongo --port 28011
>use shadow
>db.shop.count() # 总记录 = shard1 + shard2 + shard3
# 分片服务shard-1
# 如果连接的是 Secondary,先执行 rs.slaveOk()
./bin/mongo --port 28021
shard1:PRIMARY>use shadow
shard1:PRIMARY>db.shop.count()
# 分片服务shard-2
# 如果连接的是 Secondary,先执行 rs.slaveOk()
./bin/mongo --port 28031
shard2:PRIMARY>use shadow
shard2:PRIMARY>db.shop.count()
# 分片服务shard-3
# 如果连接的是 Secondary,先执行 rs.slaveOk()
./bin/mongo --port 28041
shard3:PRIMARY>use shadow
shard3:PRIMARY>db.shop.count()