业务应用场景
- 高并发、高存储、高可扩展性和可用性
- NoSql,松散型数据库
- 社交场景,存储用户信息,地理位置;游戏场景,查询方便,高效率存储和访问;物流场景,订单状态不断更新;物联网场景,存储所有接入的智能设备信息以及日志信息;视频直播,互动信息和用户信息
- 数据量大、写入操作频繁、价值较低,对事务性要求不高
- 不需要事务及复杂json支持;需要TB设置PB级别数据存储;存储的数据不丢失;大量的地理位置查询、文本查询
- 无模式,没有具体的链,类似于json的bson结构(二进制的json);文档型数据库,最像关系型数据库的非关系型数据库
mac
启动
vim ~/.bash_profile
export PATH=/usr/local/mongodb/bin:$PATH
source ~/.bash_profile
sudo mongod --dbpath=(某文件夹下的)/data/db/
- 客户端启动
mongo
- 客户端连接指定端口
mongo --host=127.0.0.1 --port=27017
配置
sudo mkdir -p single/log
sudo mkdir -p single/data/db
sudo vi single/mongod.conf
systemLog:
destination: file
path: /usr/local/mongodb/single/log/mongod.log
logAppend:true
storage:
dbPath: /usr/local/mongodb/single/data/db
journal:
enabled:true
processManagement:
fork:true
net:
bindIp: localhost
port:27017
- 配置文件启动,报
1或者48
的错误,一般是配置文件写错了,配置文件是yml
的格式,空格缩近
sudo mongod -f mongod.conf
sudo chown apple /usr/local/mongodb/replica-sets/myrs_27019/log/mongod.log
sudo chown apple /usr/local/mongodb/replica-sets/myrs_27019/data/db/
ps aux | grep mongod
关闭
use admin
db.shutdownServer()
ps aux | grep mongod //查看进程pid
sudo kill -2 pid
基本常用命令
数据库操作
- 查看所有数据库
show dbs
- 新建数据库
use articledb
,刚创建时只存在内存中,并没有持久化,当有一个集合的时候才会持久化
- 查看当前数据库
db
admin
存放用户信息权限等;local
这个数据永远不会被复制,存储限于本地单台服务器的任意集合;config
用于Mongo分片设置事,在内部使用,保存分片相关信息
- 删除数据库
db.dropDatabase()
集合操作
- 显式创建
db.createCollection("article")
- 查看集合
show collections
- 删除集合
db.article.drop()
文档操作
插入和查询
- 单条插入
db.comment.insert({"articleid":"10000", "content":"好累", "userid":"102"})
- 查询
db.comment.find()
- 多条插入
db.comment.insertMany([{"_id":"1", "articleid":"10000", "content":"好累", "userid":"102"},{"_id":"2", "articleid":"10001", "content":"不累", "userid":"105"},{"_id":"3", "articleid":"10002", "content":"好不累", "userid":"104"},{"_id":"4", "articleid":"10003", "content":"不好累", "userid":"103"}]);
- 条件查询
db.comment.find({"_id":"1"})
- 条件查询返回一条数据
db.comment.findOne({articleid:"10000"})
- 显示部分字段
db.comment.find({articleid:"10000"},{articleid:1, content:1, _id:0})
_id
默认显示,排除需要置0;需要显示的字段置1
- 插入多条有异常通过
try...catch
捕捉
try {
} catch(e) {
print(e);
}
更新
- 覆盖修改
db.comment.update({_id:"1"},{content:"一点都不累"})
,第二个参数覆盖整条数据,默认修改第一条符合条件的记录,如果没有这个属性则自动添加
- 局部修改
db.comment.update({_id:"2"},{$set:{content:"一点都不累",userid:"200"}})
- 批量修改
db.comment.update({userid:"104"}, {$set:{content:"累不累"}}, {multi:true})
,设置第三个参数
- 列值增长
db.comment.update({"userid":"104"},{$inc:{likenum:NumberInt(32)}})
,增加32
删除
- 条件删除
db.comment.remove({_id:ObjectId("6142ab897f0555879ed562a7")})
- 删除所有
db.comment.remove({})
查询
db.comment.count()
db.comment.count({userid:"104"})
- 查询前几条
db.comment.find().limit(2)
- 跳过前几条
db.comment.find().limit(2).skip(2)
- 排序查询
db.comment.find({}, {userid:1}).sort({userid:1})
1为升序,-1为降序
- 正则表达式查询
db.comment.find({content:/不/})
,用正则表达式去匹配内容
- 比较查询
//userid大于102的文档
db.comment.find({userid:{$gt:"102"}})
lt 小于
gte 大于等于
lte 小于等于
ne 不等于
- 包含查询
db.comment.find({_id: {$in:["2","3"]}})
- 条件查询
db.comment.find({$and:[{_id:{$gt:"1"}}, {userid:{$lt:"105"}}]})
db.comment.find({$or:[{_id:{$lt:"2"}},{_id:{$gte:"4"}}]})
db.comment.find({$or:[{_id:{$lt:"2"}},{$and:[{likenum:NumberInt(1000)},{_id:ObjectId("6142ae7e7f0555879ed562a8")}]}]})
索引
索引管理
db.comment.getIndexes()
"v" : 2, 索引引擎版本
"key" : {
"_id" : 1
},
"name" : "_id_", 索引名
"ns" : "articledb.comment" 集合名
- 创建索引
db.comment.createIndex({userid:1})
- 创建复合索引
db.comment.createIndex({userid:1, articleid:-1})
- 删除索引
db.comment.dropIndex({userid:1})
db.comment.dropIndex("userid_1_articleid_-1")
db.comment.dropIndexes()
索引使用
- 执行计划,查询性能。
db.comment.find({userid:"104"}).explain()
,可以查看这个条件是否用通过索引查询,先获取到IXSCAN
索引集合,再通过FETCH
找到目标字段
覆盖查询
- 查询的内容就是索引,并且需要返回的内容也就是索引,就可以直接在索引中找,不需要通过索引继续去集合中找了
db.comment.find({userid:"104"}, {userid:1,_id:0})
Spring集成mongodb
配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
spring:
data:
mongodb:
host: 127.0.0.1
database: articledb
port: 27017
实体类
@Document(collection="comment")
@Id
private String id;
@Field("content")
private String content;
@Indexed
private String userid;
- 标注符合索引,标注在类上。建议在命令台创建,因为未来建立的索引,可能现在还没有对应的属性值
@CompoundIndex( def = "{'userid': 1, 'nickname': -1}")
增删改查
public interface CommentRepository extends MongoRepository<Comment, String> {
}
@Service
public class CommentService {
@Autowired
private CommentRepository commentRepository;
public void saveComment(Comment comment){
commentRepository.save(comment);
}
public void updateComment(Comment comment){
commentRepository.save(comment);
}
public void deleteCommentById(String id){
commentRepository.deleteById(id);
}
public List<Comment> findCommentList(){
return commentRepository.findAll();
}
public Comment findCommentById(String id){
return commentRepository.findById(id).get();
}
}
案例-分页查询
Page<Comment> findByParentid(String paraentid, Pageable pageable);
public Page<Comment> findCommentListByParentid(String parentid, int page, int size) {
return commentRepository.findByParentid(parentid, PageRequest.of(page-1,size));
}
Page<Comment> cbp = commentService.findCommentListByParentid("3", 4, 2);
System.out.println(cbp.getTotalElements());
for (Comment comment : cbp.getContent()) {
System.out.println(comment);
}
MongoTemplate-实现评论点赞
@Autowired
private MongoTemplate mongoTemplate;
public void updateCommentLikenum(String id) {
Query query = Query.query(Criteria.where("_id").is(id)).addCriteria(Criteria.where("likenum").lt(889));
Update update = new Update();
update.inc("likenum");
mongoTemplate.updateFirst(query,update,Comment.class);
}
副本集
- 一组维护相同数据集的服务,可提供冗余和高可用性
- 主从复制,有一个固定的主和固定的从;副本集,没有固定的主节点,整个集群通过投票机制选出一个主节点,总有一个活跃点(主)和一个或者多个备份节点(从)
- 两种类型。主节点,数据操作的主要节点,可读写;次要节点,数据冗余备份节点,可以读或者选举
- 三种角色。主要成员,主要接受所有写操作;副本成员,从主节点通过复制操作以维护相同的数据库,不可写操作,可以读操作;仲裁者,不保留任何数据的副本,只具有投票选举的作用,副本成员可以同时是仲裁者,也是一种从节点类型
搭建
replication:
replSetName: myrs
- 主节点初始化
rs.initiate()
- 查看配置
rs.conf()
- 查看状态
rs.status()
- 添加从节点
rs.add("127.0.0.1:27018")
- 添加仲裁节点
rs.addArb("127.0.0.1:27019") / rs.add("127.0.0.1:27019", true)
- 修改主节点ip
var config = rs.config()
config.members[0].host="180.76.159.126:27017"
rs.reconfig(config)
数据读写操作
db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光明媚","userid":"1001","nickname":"Rose","createdatetime":new Date()})
db.comment.find()
- 从节点设置 只可以读
rs.slaveOk()
- 从节点取消读权限
rs.slaveOk(false)
- 从节点只可以读
db.comment.find()
仲裁节点
- 不存放任何业务数据,可以登录查看
- 设置
rs.slaveOk()
- 只有一个库
local 0.000GB
只有配置信息
选举原则
- 触发选举。主节点故障;主节点网络不可大(默认心跳信息10秒);人工干预
rs.stepDown(600)
- 选举规则。票数最高,大多数成员支持;票数相同时,较新的节点获胜,通过操作日志
oplog
对比
- 可以设置某台服务器的优先级,优先级越高,越有可能成为主节点。通过
rs.conf()
可以查看"priority" : 1,
,仲裁节点优先级是0,不可能成为主节点
- 修改优先级
cfg=rs.conf()
cfg.members[1].priority=2
rs.reconfig(cfg)
故障测试
- 副本节点宕机,不影响主节点的写入,重新连接后,自动同步数据
- 主节点宕机,触发选择,副本集是3,仲裁节点也给从节点投了一票,从节点被选举成了主节点
- 仲裁节点和主节点都宕机,就剩从节点自己,但是没有大多数成员,只有自己本身,但是当重连之后,会成为主节点;当剩下的从节点数量为3个以上时,就会立即选出新的主节点
- 仲裁节点和从节点都宕机,过了10秒,服务降级,被降级成从节点,重连后,还是恢复主节点身份
Spring连接副本集
mongodb://host1,host2,host3/articledb? connect=replicaSet&slaveOk=true&replicaSet=副本集名字
spring:
data:
mongodb:
uri连接
uri: mongodb://127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
分片集群
- 副本集,所有数据都是同步的,只能存在一台服务器上
- 分片,将数据拆分,将其分散在不同的机器上
- 解决系统增长的方法。垂直扩展,加硬盘;水平扩展,加机器
- 组件。分片,存储数据的,每个角落分片都可以部署为副本集;mongos,路由,在客户端应用程序和分片集群之间提供借口;config servers,调度配置,配置服务器存储群集的元数据和配置设置,必须部署为副本集
- 用户通过路由访问配置集,查询到数据存在哪个分片,再去分片中查找目标数据
配置分片和配置文件
replication:
//副本集名称
replSetName: myshardrs01
sharding:
//分片角色
clusterRole: shardsvr
replication:
replSetName: myconfigrs
sharding:
clusterRole: configsvr
- 初始化分片副本集,与上面的副本集操作一样
- 初始化配置分片,没有仲裁节点,都是副本节点
配置路由
- 路由节点配置文件,不需要data目录,只需要log目录
systemLog:
destination: file
path: /usr/local/mongodb/sharded_cluster/mymongos_27017/log/mongod.log
logAppend: true
processManagement:
fork: true
net:
bindIp: localhost
port: 27017
sharding:
//指定配置节点副本集
configDB: myconfigrs/127.0.0.1:27019,127.0.0.1:27119,127.0.0.1:27219
sh.addShard("myshardrs01/localhost:27018,127.0.0.1:27118,127.0.0.1:27218")
sh.addShard("myshardrs02/localhost:27318,127.0.0.1:27418,127.0.0.1:27518")
- 路由查看状态
sh.status()
- 路由开启分片功能,打开对应的数据库
sh.enableSharding("articledb")
- 对集合进行分片,指定集合和分片键。分片规则,哈希策略;范围策略。
一个集合只能按照一个策略进行分片,一旦对一个集合分片,分片键和分片值就不可改变。 如:不能给集合选择不同的分片键、不能更新分片键的值。
sh.shardCollection("articledb.comment", {"nickname":"hashed"})
sh.shardCollection("articledb.author", {"age":1})
- 增加路由节点,一样的配置,不同的端;正常连接后,可以直接使用,不需要再配置
使用
- 通过路由客户端,循环插入1000条数据,测试哈希策略
for(var i=1;i<=1000;i++) {db.comment.insert({_id:i+"",nickname:"BoBo"+i})}
- 测试范围规则,因为默认的数据块尺寸为64m,为了测试需要改小
//修改数据块
use config
db.settings.save({_id:"chunksize", value: 1})
//插入
for(var i=1;i<=20000;i++) {db.author.save({"name":"BoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoB oBoBoBoBoBoBoBoBo"+i,"age":NumberInt(i%120)})}
//改回来
db.settings.save({_id:"chunksize", value: 64})
{ "age" : { "$minKey" : 1 } } -->> { "age" : 0 } on : myshardrs01 Timestamp(2, 0)
{ "age" : 0 } -->> { "age" : 46 } on : myshardrs01 Timestamp(3, 0)
{ "age" : 46 } -->> { "age" : 92 } on : myshardrs02 Timestamp(3, 1)
{ "age" : 92 } -->> { "age" : 111 } on : myshardrs02 Timestamp(1, 6)
{ "age" : 111 } -->> { "age" : { "$maxKey" : 1 } } on : myshardrs02 Timestamp(1, 3)
spring链接分片集群
spring:
data:
mongodb:
uri: mongodb://127.0.0.1:27017,127.0.0.1:27117/articledb
安全认证
- 通过角色对用户授予相应数据库资源的操作权限,每个角色当中的权限可以显式指定,也可以通过继承其他角色的权限
- 查看所有内置权限
db.runCommand({rolesInfo:1, showBuiltinRoles:true})
单实例环境
- 创建超级管理员用户
db.createUser({user:"myroot", pwd: "12345", roles:["root"]})
,只能在admin
下
- 创建专门管理admin的用户
db.createUser({user:"myadmin",pwd:"123456",roles: [{role:"userAdminAnyDatabase",db:"admin"}]})
- 查看已经创建的用户情况
db.system.users.find()
- 删除用户
db.dropUser("myadmin")
- 修改密码
db.changeUserPassword("myroot", "111111")
- 验证用户
db.auth("myroot", "111111")
,登陆前,要切换到对应的数据库
- 报错
too many users are authenticated
,一次最好就认证一个账户,不要一个客户端多次认证
- 创建普通用户
db.createUser({user: "manager", pwd: "123456", roles: [{ role: "readWrite", db: "articledb" }]})
- 服务端开启安全认证
mongod -f mongod.conf --auth
securit:
authorization: enabled
spring安全连接
spring:
data:
mongodb:
host: 127.0.0.1
database: articledb
port: 27017
username: "manager"
password: "123456"
副本集环境
- admin下创建超级管理员
db.createUser({user:"myroot",pwd:"123456",roles:["root"]})
- 生成key文件
sudo openssl genrsa -out mongo.keyfile 1024
sudo chmod 400 mongo.keyfile
sudo cp mongo.keyfile myrs_27019
security:
keyFile: /usr/local/mongodb/replica-sets/myrs_27017/mongo.keyfile
authorization: enabled
- 其他操作跟单实例一致
- 创建普通账户
db.createUser({user:"zhangsan",pwd:"123456",roles:["readWrite"]})
- spring访问,
yml
配置 uri: mongodb://zhangsan:123456@127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
分片集群