2.为什么要使用MongoDB?
username:'123',
password:'123'
}
SQL类型的数据库是正规化的,可以通过主键或者外键的约束保证数据的完整性与唯一性,所以SQL类型的数据库常用于对数据完整性较高的系统。MongoDB在这一方面是不如SQL类型的数据库,且MongoDB没有固定的Schema,正因为MongoDB少了一些这样的约束条件,可以让数据的存储数据结构更灵活,存储速度更加快。
MongoDB保留了关系型数据库即时查询的能力,保留了索引(底层是基于B tree)的能力。这一点汲取了关系型数据库的优点,相比于同类型的NoSQL redis 并没有上述的能力。
MongoDB自身提供了副本集能将数据分布在多台机器上实现冗余,目的是可以提供自动故障转移、扩展读能力。
4.C/S服务模型
5.完善的命令行工具
1.切换数据库
2.插入语法
db.users.save({username:"smith"})
-
区别: 若新增的数据中存在主键 ,insert() 会提示错误,而save() 则更改原来的内容为新内容。如:
已存在数据:{_id : 1, " name " : " n1 " },再次进行插入操作时,insert({_id : 1, " name " : " n2 " }) 会报主键重复的错误提示,save({ _id : 1, " name " : " n2 " }) 会把 n1 修改为 n2 。 -
相同点: 若新增的数据中没有主键时,会增加一条记录。已存在数据:{ _id : 1, " name " : " n1 " },再次进行插入操作时,insert({ " name " : " n2 " }) 插入的数据因为没有主键,所以会增加一条数据,save({ " name " : " n2 " }) 增加一条数据。
3.查找语法
db.users.count()
4.更新语法
//把用户名为smith的用户的国家改成Canada
db.users.update({username:"smith"},{$unset:{country:1}})
//把用户名为smith的用户的国家字段给移除
db.users.update({username:"jones"},{$set:{favorites:{movies:["casablance","rocky"]}}})
//这里主要体现多值修改,在favorties字段中添加多个值
db.users.update({"favorites.movies":"casablance"},{$addToSet:{favorites.movies:"the maltese"}},false,true)
//多项更新
5.删除语法
db.foo.remove({favorties.cities:"cheyene"}) //根据条件进行删除
db.drop() //删除整个集合
6.索引相关语法
//创建一个升序索引
db.numbers.getIndexes()
//获取全部索引
7.基本管理语法
//查询所有数据库
show collections
//显示所有表
db.stats()
//显示数据库状态信息
db.numbers.stats()
//显示集合表状态信息
db,shutdownServer()
//停止数据库
db.help()
//获取数据库操作命令
db.foo.help()
//获取表操作命令
tab 键 //能自动帮我们补全命令
1.使用maven引入jar包
<groupId>org.mongodbgroupId>
<artifactId>mongodb-driver-syncartifactId>
<version>3.8.0-beta3version>
dependency>
2.创建一个访问客户端
3.获取集合数量
MongoClient client = this.getClient();
MongoCollection collections= client.getDatabase("mongodb_db_name").getCollection("mongodb_collection_name");
return collections.count();
}
4.查询集合
MongoClient client = this.getClient();
MongoCollection collections= client.getDatabase("mongodb_db_name").getCollection("mongodb_collection_name");
List list = new ArrayList (Integer.valueOf(config.getPro("sync_limit")));
collections.find(params).sort(sort).skip(skip).limit(limit).forEach(new Block () {
@Override
public void apply(Document document) {
list.add(document);
}
});
return list;
}
1.需要关注MongoDB的自身的特性
2.需要关注系统本身的读写特性
3.关注MongoDB schema 的设计模式
-
内嵌与引用 :当子对象总是出现在父对象的上下文中时,使用内嵌文档;否则将子对象单独存一个集合。
-
一对多的关系 :在“多”的集合关系中添加id指向依赖的id。
-
多对多 :在其中一种对应关系中使用对象数组指向另外一个对象。
-
树 :具化路径,在树中的每个节点都包含一个path字段,该字段具体保存了每个节点祖先的id。
-
动态属性 :可以为不同的动态属性添加索引,如果需要将属性圈在一个范围,那么可以通过key-value的方式,然后在统一的key上面加索引。
-
关于事务 :如果需要事务支持,那么只能选择另一种数据库,或者提供补偿性事务来解决事务的问题。
-
不能创建没用的索引
-
不能在同一个字段中存不同的类型
-
不能把多类实体都放在一个集合里 不能创建体积大、嵌套深的文档
-
不能过多的创建集合,集合、索引、数据库的命名空间都是有限的
-
不能创建无法分片的集合
4.关注MongoDB里面一些具体细节
system.indexes //存储当前数据库的所有索引定义
1.索引的经验法则
2.索引类型
(2)复合索引
(3)唯一性索引
(4)稀疏索引
如索引的字段会出现null的值,或是大量文档都不包含被索引的键。
3.索引的构建问题
4.识别慢查询
db.setProfillingLevel(2) //使用解刨器,将记录每次的读写到日志
db.setProfillingLevel(1) //只记录慢(100ms)操作
-
scanOrder 字段表明没有使用索引
-
cursor当没有索引时,用的是BasicCursor,当使用索引时使用的是BtreeCursor
-
n 表示需要返回的结果集
-
nscanned表示需要遍历的文档数 indexBounds 表示索引边界
1.为什么要使用副本集
2.构建方式
rs.add("localhost:40001")
rs.add("localhost:40002",{arbiterOnly:true})
3.监控
rs.status()
4.副本集的工作原理
-
如果从节点在主节点的oplog里找不到它所同步的点,那么会永久停止复制
-
一旦某个从节点没能 在主节点的oplog里找到它已经同步的点,就无法再保证这个从结点的完美副本
-
replset.minvalid 包含指定副本集成员的初始化同步信息
-
system.replset 保存在副本集配置文档
-
system.indexes 标准索引说明容器
-
me slaves 主要用于写关注
-
ts 保存了该条目的BSON时间戳
-
t 是从纪元开始的描述
-
i是计数器
-
op 表示操作码
-
ns 标明了有关的命名空间
5.心跳检测
6.故障转移
7.提交与回滚
8.驱动与复制
1.为什么需要分片
2.分片的工作原理
-
分片:每个分片都是一个副本集
-
mongos路由器:是一个路由器,将读写请求指引到合适的分片上
-
配置服务器config:持久化分片集群的元数据,包括:全局集群配置;每个数据库、集合和特定范围数据位置;一份变更记录,保存了数据在分片之间进行迁移的历史信息。配置服务器之间不是副本集形式存在,mongos向配置服务器提交信息时是两阶段提交,保证配置服务器之间的一致性。
3.分片实战
sh.addShard() //添加分片
db,getSiblingDB("config").shards.find() //查看分片列表
sh.status() //分片详情
sh.enableSharding("cloud-docs") //开启一个数据库上的分片
db.getSiblingDB("config").databases,find() //查看数据库列表
sh.shardCollection("cloud-docs.spreadsheets",{username:1,_id:1}) //使用一个分片键定义一个分片集合spreadsheets,根据用户名进行切分
sh.getSiiblingDB("config").collections.findOne() //查看集合列表
db.chunks.count() //查看块的个数
db.chunks.findOne() //查看块的信息
db.changelog.count(}what:"split"|) //查看块切分日志
db.changelog.find({what:"moveChunk.commit"}).count() //查看日志迁移记录
4.分片的查询与索引
-
针对性查询:查询包含分片键
-
全局查询或分散/聚集查:查询不包含分片键
-
查询过程:通过分片键将查询路由给指定分片,一旦到了某个分片上,由分片自行决定使用哪个索引来执行该查询
5.选择分片键
(2)低效的分片键
-
分布性差:如使用BSON对象ID,那么会导致所有最新插入的文档都会落到某个很小的连续范围,无法分散插入
-
缺乏局部性:升序分片键有明确的方向,完全随机的分片键则根本没有方向。前者无法分散插入,后者插入分散,如使用MD5作为分片键
-
将插入数据均匀分布到各个分片上
-
保证CRUD操作能够利用局部性 有足够的粒度进行块拆分
-
满足这些要求的分片键通常由两个字段组成,第一个是粗粒度的,第二个粒度较细
6.生产环境中的分片
-
复制mongod:需要独立的部署服务器
-
配置服务器:配置服务器不需要有自己的机器
-
副本集每个成员,无论是完整的副本集节点还是仲裁节点,都需要放在不同的机器上 每个用于复制的副本集成员都需要有自己的机器
-
副本集仲裁节点很轻量级,和其他进程共用一台机器即可
-
配置服务器也可以选择与其他进程共用一台机器
//手动拆分块
sh.moveChunk("cloud-docs.spreadsheets",{username:"chen"},"shardB")
//手动将某分块移至分片B
db.runCommand({removeshard:"shard-1/arete:30100,arete:30101"})
//删除分片
db.runCommand({moveprimary:"test",to:"shard-0-test-rs"});
//移动主分片
sh.setBalancerState(false);
//停止均衡器,此时均衡器将进行最后一轮均衡
db.locks.find({_id:"balancer"});
sh.isBalancerRunning();
//查看均衡器状态,任何状态大于0 的状态值都说明均衡器仍在进行中
1.部署
mongodb写入数据时会使用到CPU,但是mongodb写入时间一次只用到一个核,如果有频繁的写入行为,可以通过分片来解决这个问题
2.安全
//创建用户,最后一个参数指定是否只读
3.数据的导入与导出
mongoexport
4.服务器配置
但是Journaling日志会消耗内存,所以可以在主库上面关闭,在从库上面启动
可以单独为Journaling日志使用一块固态硬盘
5.日志
-vvvvv 选项(v越多,输出越详细)
db.runCommand({logrotare:1}) 开启滚动日志
6.数据库监控命令
-
globalLock 表示服务器花在写锁上面的总时间
-
mem显示了如何使用内存
-
bits 表明这台机器的位长
-
resident 表示占用物理内存数量
-
virtual 表示使用的虚拟内存
7.mongostat
8.web控制台
9.备份与恢复
10.压紧与修复
db.runCommand({repairDatabase:1}) 修复单个数据库
修复就是根据Jourling文件读取和重写所有数据文件并重建各个索引
db.runCommand({compact:"spreadsheets"})
11.性能调优
如果喜欢本篇文章,欢迎转发、点赞。关注订阅号「Web项目聚集地」,回复「技术博文」即可获取更多图文教程、技术博文、学习资源。