MongoDB
概念
下载地址:https://www.mongodb.com/download-center#community
1.简述MongoDB
MongoDB[1] 是一个基于分布式文件存储的数据库。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。
在高负载的情况下,添加更多的节点,可以保证服务器性能。
MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
2.什么是分布式
2.1分布式计算的优点
可靠性(容错):
分布式计算系统中的一个重要的优点是可靠性。一台服务器的系统崩溃并不影响到其余的服务器。
可扩展性:
在分布式计算系统可以根据需要增加更多的机器。
资源共享:
共享数据是必不可少的应用,如银行,预订系统。
灵活性:
由于该系统是非常灵活的,它很容易安装,实施和调试新的服务。
更快的速度:
分布式计算系统可以有多台计算机的计算能力,使得它比其他系统有更快的处理速度。
开放系统:
由于它是开放的系统,本地或者远程都可以访问到该服务。
更高的性能:
相较于集中式计算机网络集群可以提供更高的性能(及更好的性价比)。
2.2分布式计算的缺点
故障排除:
故障排除和诊断问题。
软件:
更少的软件支持是分布式计算系统的主要缺点。
网络:
网络基础设施的问题,包括:传输问题,高负载,信息丢失等。
安全性:
开发系统的特性让分布式计算系统存在着数据的安全性和共享的风险等问题。
3.MongoDB特点
它的特点是高性能、易部署、易使用,存储数据非常方便。主要功能特性有:
*面向集合存储,易存储对象类型的数据。
*模式自由。
*支持动态查询。
*支持完全索引,包含内部对象。
*支持查询。
*支持复制和故障恢复。
*使用高效的二进制数据存储,包括大型对象(如视频等)。
*自动处理碎片,以支持云计算层次的扩展性。
*支持RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
*文件存储格式为BSON(一种JSON的扩展)。
*可通过网络访问。
4.与oracle mysql 的对比
4.1 MongoDB 术语与SQL术语
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins |
| 表连接,MongoDB不支持 |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
4.2 数据存储格式比较
5.PDNMS,NOSQL简述
MongoDB使用的是NoSql
5.1 RDBMS
- 高度组织化结构化数据
- 结构化查询语言(SQL) (SQL)
- 数据和关系都存储在单独的表中。
- 数据操纵语言,数据定义语言
- 严格的一致性
- 基础事务
5.2 NOSQL
- 代表着不仅仅是SQL
- 没有声明性查询语言
- 没有预定义的模式
-键 - 值对存储,列存储,文档存储,图形数据库
- 最终一致性,而非ACID属性
- 非结构化和不可预知的数据
- CAP定理
- 高性能,高可用性和可伸缩性
6.MongoDB可以使用的数据类型
类型 | 数字 | 备注 |
Double | 1 |
|
String | 2 |
|
Object | 3 |
|
Array | 4 |
|
Binary data | 5 |
|
Undefined | 6 | 已废弃。 |
Object id | 7 |
|
Boolean | 8 |
|
Date | 9 |
|
Null | 10 |
|
Regular Expression | 11 |
|
JavaScript | 13 |
|
Symbol | 14 |
|
JavaScript (with scope) | 15 |
|
32-bit integer | 16 |
|
Timestamp | 17 |
|
64-bit integer | 18 |
|
Min key | 255 | Query with -1. |
Max key | 127 |
|
操作MongoDB
1.Linux 安装MongoDB
Centos or RedHat 下安装都可
拷贝tar.gz文件到 /root/software/mongoDB 文件夹下
解压 tar -zxvf ....
移动解压文件到 /usr/local/mongodb 目录下
cd /usr/local/mongodb查看
mkdir db 创建数据库存放的路径
mkdir logs 创建存放的日志的路径
在bin目录下创建一个名为mongodb.conf的配置文件加入以下内容:
#数据库的存放路径
dbpath = /usr/local/mongodb/db
#日志文件的存放路径
logpath = /usr/local/mongodb/logs/mongodb.log
#使用追加的方式记录日志
logappend = true
#端口
port = 27017
#后台运行
fork = true
#是否开启权限验证
#auth = true
#pid File的完整路径,如果没有设置则没有pid文件
pidfilepath=/usr/local/mongodb/mongo.pid
#声明这是一个集群的分片,默认端口是28017
shardsvr=true
#设置简单的rest Api,即打开的28017端口
rest=true
为mongoDB设置系统服务
vim /etc/rc.d/init.d/mongod
根据自己安装的实际情况配置,我的配置如下:
mit -SHn 655350
#!/bin/sh
# chkconfig: - 64 36
# description:mongod
case $1 in
start)
/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/bin/mongodb.conf
;;
stop)
/usr/local/mongodb/bin/mongo 127.0.0.1:27017/admin --eval "db.shutdownServer()"
;;
status)
/usr/local/mongodb/bin/mongo 127.0.0.1:27017/admin --eval "db.stats()"
;;
esac
Chmod -R 777 /etc/rc.d/init.d/mongod
关闭防火墙
Centos: service iptables stop
RedHat: systemctl stop firewalld
开启mongodb 服务,因为我们为mongoDB配置了系统服务,固如此即可
service mongod start
若出现下面这中情况,则是因为没有正常关闭导致的
ps -ef |grep mongod 查看所有进程
lsof -i:27017 查看指定端口的进程
cd /usr/local/mongodb/bin
进入mongo shell界面:
./mongo
如此成功:
exit quit 都可以退出 mongo shell
关闭mongodb 服务:
service mongod stop
2.一些简单的 mongo shell 命令
可以到菜鸟教程中去看
提供一个网址:http://www.cnblogs.com/cswuyg/p/4595799.html
查看所有数据库: show dbs
显示当前用户: show users
得到当前数据库版本:db.version()
得到当前数据库状态: db.stats()
得到数据库的链接地址:db.getMongo()
修复当前数据库: db.repairDatabase();
从指定机器上复制数据库到本地数据库: db.copyDatabase("mydb", "temp", "127.0.0.1");
查看当前使用的数据库: db
切换数据库: use 数据库名
查看数据库下的所以集合: show collections
查看集合下的所有文件:db.集合名.find() #db就指当前使用的数据库
查看帮助文档: help
在数据库级别查看帮助信息:db.help()
在集合级别查看帮助信息:db.集合名.help()
删除指定集合:db.集合名.drop or db.集合名.remove({}) 删除集合中的所有内容推荐使用第一种,因为remove删除方式需要进行一个全局的查询,速度效率都比较慢
删除数据库 db.dropDatabase() #需要删除哪个数据库就要先切换到哪个数据库
清屏: cls
创建数据库:use 数据库名 #注意,此时我们是没用创建mongodb数据库的,因为该数据库中还未存在有集合,mongodb会监测到该数据库内容为空,并在我们退出该数据库的时候自动清除该数据库
创建集合:db.createCollection(“集合名称”) #db.createCollection(“message”)
创建一条数据:xiao = {"name":"肖亮亮","age":18,"sex":"男","createTime":new Date()}
向集合中插入一条数据: db.集合名.insert(数据名称)
查询该集合下的所有数据: db.集合名.find() #当查询的数据过多的时候你可以用it 来查看下一页的信息
得到该集合下的一条数据: db.集合名.findOne()
关键字:$exists 小于:$lt 大于:$gt 小于等于:$lte 大于等于:$gte 不等于:$ne And用,分隔就好了 or : $or print("输出到shell") in:$in not in :$nin
函数: count()
分页:db.message.find().limit(1).skip(1) #即表示显示第一条数据后面的一条数据
排序:db.message.find().sort({字段名:1}) #1表示升序 -1表示降序
删除用户:db.system.users.remove({user:"haha"})
3.5函数,聚合表达式
count(): db.集合名.find().count()
distinct(): db.集合名.distinct("addr",{age:{$gt:18}}) #addr 是去从字段,后面的是条件
表达式 | 描述 | 实例 |
$sum | 计算总和。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}]) |
$min | 获取集合中所有文档对应值得最小值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}]) |
$max | 获取集合中所有文档对应值得最大值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}]) |
$push | 在结果文档中插入值到一个数组中。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}]) |
$addToSet | 在结果文档中插入值到一个数组中,但不创建副本。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}]) |
4.关于用户和权限问题
创建用户:
db.createUser(
... {
... user: "xiao",
... pwd: "xiao",
... roles: [ { role: "readWrite", db: "xiao" } ]
... }
... )
注意,若你想要配置的用户权限验证起作用,将 mongodb.conf 里面的auth解开即可
重启mongod 再次./mongo 进入shell的时候use xiao db.auth("xiao","xiao")即可验证成功
roles:指定用户的角色,可以用一个空数组给新用户设定空角色;在roles字段,可以指定内置角色和用户定义的角色。role里的角色可以选:
1. 数据库用户角色:read、readWrite;
2. 数据库管理角色:dbAdmin、dbOwner、userAdmin;
3. 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
4. 备份恢复角色:backup、restore;
5. 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
6. 超级用户角色:root
// 这里还有几个角色间接或直接提供了系统超级用户的访问(dbOwner、userAdmin、userAdminAnyDatabase)
7. 内部角色:__system
Read:允许用户读取指定数据库readWrite:允许用户读写指定数据库
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问
system.profileuserAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。
root:只在admin数据库中可用。超级账号,超级权限
5.java代码的链接与调用
<dependencies>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>bson</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies>
package com;
import java.util.ArrayList;
import java.util.List;
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
public class MongoDBJDBC {
// MongoDB链接
private static MongoClientmongoClient;
// 得到的数据库对象
private static MongoDatabasemongoDatabase;
// 操作的集合名称
private static final StringCOLLECTION_NAME ="message";
// 集合链接对象
private static MongoCollection<Document>collection;
public static void main(String[]args) {
getMogoClient();
createCollection();
insert();
select();
delete();
update();
select();
deleteCollection();
}
public static void getMogoClient() {
try {
// ServerAddress()两个参数分别为 服务器地址 和 端口
ServerAddress serverAddress = new ServerAddress("192.168.1.120", 27017);
List<ServerAddress> addrs = new ArrayList<ServerAddress>();
addrs.add(serverAddress);
// MongoCredential.createScramSha1Credential()三个参数分别为 用户名 数据库名称 密码
MongoCredential credential = MongoCredential.createScramSha1Credential("dba","xiao","dba".toCharArray());
List<MongoCredential> credentials = new ArrayList<MongoCredential>();
credentials.add(credential);
// 通过连接认证获取MongoDB连接
mongoClient = new MongoClient(addrs,credentials);
// 连接到数据库
mongoDatabase = mongoClient.getDatabase("xiao");
System.out.println("Connect to database successfully");
} catch (Exception e) {
System.err.println(e.getClass().getName() +": " +e.getMessage());
}
}
public static void createCollection() {
collection = mongoDatabase.getCollection(COLLECTION_NAME);
if (null ==collection) {
mongoDatabase.createCollection(COLLECTION_NAME);
collection = mongoDatabase.getCollection(COLLECTION_NAME);
}
System.out.println("得到的条数: " +collection.count());
}
private static void insert() {
System.out.println("向数据集中插入数据开始:");
Document document = new Document();
List<Document> dbList = new ArrayList<Document>();
document.put("name","小李");
document.put("age", 30);
document.put("address","北京");
dbList.add(document);
Document document2 = new Document();
document2.put("name","小张");
document2.put("age", 25);
document2.put("address","天津");
dbList.add(document2);
collection.insertMany(dbList);
System.out.println("向数据集中插入数据完成!");
System.out.println("------------------------------");
}
public static void delete() {
System.out.println("删除【小张】!");
Document document = new Document();
document.put("name","小张");
DeleteResult result = collection.deleteMany(document);
long lo =result.getDeletedCount();
System.out.println("删除成功,共删除 :" +lo);
System.out.println("现数据总条数: "+collection.count());
}
public static void update() {
Document document = new Document();
document.put("age",30);
Document document2 = new Document();
document2.put("name","小罗");
UpdateResult result = collection.replaceOne(document,document2);
System.out.println("修改所影响的行数: "+result.getModifiedCount());
}
public static void select() {
System.out.println("现数据总条数: "+collection.count());
FindIterable<Document> find = collection.find();
System.out.println("得到剩余的数据总条数: "+collection.count());
for (Document document : find) {
System.out.println("id: "+document.get("_id")+" name: "+document.getString("name")+" age: "+document.getInteger("age",0)+" address: "+document.getString("address"));
}
}
public static void deleteCollection(){
collection.drop();
System.out.println("最后操作,删除该集合!!");
}
}
6.MongoDB集群配置Replica Set方式
http://www.linuxidc.com/Linux/2015-02/113017.htm
Mongodb的三种集群方式的搭建:Replica Set / Sharding / Master-Slaver
使用三个虚拟机 192.168.1.120 192.168.1.121 192.168.1.122 配置如上
SECONDARY是不允许读写的, 在写多读少的应用中,使用Replica Sets来实现读写分离。
通过在连接时指定或者在主库指定slaveOk,由Secondary来分担读的压力,Primary只承担写操作。对于replica set 中的secondary 节点默认是不可读的,
vim /etc/rc.d/init.d/mongod
只要把为mongoDB设置系统服务的文件改为如下:
mit -SHn 655350
#!/bin/sh
# chkconfig: - 64 36
# description:mongod
case $1 in
start)
/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/bin/mongodb.conf --replSet repset
;;
stop)
/usr/local/mongodb/bin/mongo 127.0.0.1:27017/admin --eval "db.shutdownServer()"
;;
status)
/usr/local/mongodb/bin/mongo 127.0.0.1:27017/admin --eval "db.stats()"
;;
esac
其他配置和上面完全一样
分别开启三个mongod 并关闭防火墙
随便./mongo 进入一个shell
定义一个变量:
config = { _id:"repset",
members:[
{_id:0,host:"192.168.1.120:27017"},
{_id:1,host:"192.168.1.121:27017"},
{_id:2,host:"192.168.1.122:27017"}
]}
初始化副本集: rs.initiate(config)
查看集群点状态: rs.status()
找到主节点./mongo进入shell
测试集群 :db.testdb.insert({"demo":"demo"})
登陆从属节点:rs.slaveOk() 设置secondary 为可读
之后db.testdb.find() 则可得到信息
如此,集群搭建完毕
7.与Spring整合
注意事项:
误区一、文档顺序和插入顺序一致?
单线程情况
ObjectId中的timestamp、machine、pid、inc都可以保证唯一,因为在同一台机器,同一个进程。
这里有一个问题,mongodb的操作时多线程的。a、b、c...几个线程进行入库操作时,不能保证哪一条可以在另外一条之前,所以会是乱序的。
多线程、多机器或多进程情况
再看下ObjectId中mache、pid不能保证唯一。那么则数据更加会是乱序的。
解决办法:
由于collection集合中数据是无序的(包括capped collection),那么,最简单的办法是对ObjectId进行排序。