NoSQL简介
MongoDB是一个基于分布式文件存储的数据库,由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案
NoSQL=NOT Only SQL
ACID规则:
- A(Atomicity)原子性 要么全做完,要么都不做
- C(Consistency)一致性 a+b=10;a改变,b一定也要改变
- I(Isolation)独立性 事物之间不会互相影响
- D(Durability)持久性 修改永久有效
分布式计算的优点:
- 可靠性
- 可扩展性
- 资源共享
- 灵活性
- 更快的速度
- 开放系统
- 更高的性能
缺点
- 更少的软件支持
- 网络设施
- 安全性
什么是NoSQL
NoSQL,指的是非关系型的数据库,用于超大规模数据的存储
为什么使用NoSQL?
CAP定理(CAP theorem)
三点:
- 一致性(Consistency):所有节点在同一时间具有相同的数据
- 可用性(Availability):保证每一个请求不管成功呢或者是失败都有响应
- 分隔容忍(Partition tolerance):系统中任何信息的丢失或者失败都有响应
CA/CP/AP
CA-单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大
CP-满足一致性,分区容忍性的系统,通常性能不是特别高
AP-满足可用性,分区容忍性的系统,可能对一致性要求要低一些
ACID vs BASE
ACID | BASE |
---|---|
原子性(Atomicity) | 基本可用(Basically Available) |
一致性(Consistency) | 软状态/柔性事务(Soft state) |
隔离性(Isolation) | 最终一致性(Eventual consistency) |
持久性(Durable) |
MongDB简介
MongoDB是由C++编写的,是一个基于分布式文件存储的开源数据库系统
在高负载的情况下,添加更多的节点,可以保证服务器性能
MongoDB旨在为WEB应用程序提供可扩展的高性能数据存储解决方案
MongoDB概念解析
MongoDB概念解析
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
inex | index | 索引 |
table joins | 表连接,MongoDB支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
RDBMS与MongoDB对应的术语
RDBMS | MongoDB |
---|---|
数据库 | 数据库 |
表格 | 集合 |
行 | 文档 |
列 | 字段 |
表联合 | 嵌入文档 |
主键 | 主键(MongoDB提供了Key为_id) |
集合命名空间 | 描述 |
---|---|
dbname.system | 列出所有名字空间 |
dbname.system.indexes | 列出所有索引 |
dbname.system.profile | 包含数据库概要(profile)信息 |
dbname.system.users | 列出所有可访问数据库的用户 |
dbname.local.sources | 包含复制对端(slave)的服务器信息和状态 |
MongoDB数据类型
数据类型 | 描述 |
---|---|
String | 字符串,存储数据常用懂得数据类型,在MongoDB中,UTF-8编码的字符串才是合法的 |
Integer | 整型数值,用于存储数值,根据你所采用的服务器,可分为32位或64位 |
Boolean | 布尔值,用于存储布尔值 |
Double | 双精度浮点值,用于存储浮点值 |
Min/Max keys | 将一个值与BSON(二进制的JSON)元素的最低值和最高值相对比 |
Array | 用于将数组或列表或多个值存储为一个键 |
Timestamp | 时间戳,记录文档修改或添加的具体时间 |
Object | 用于内嵌文档 |
Null | 用于创建空值 |
Symbol | 符号,该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言 |
Date | 日期时间时间,用UNIX时间格式来存储当前日期或时间,你可以指定自己的日期时间 |
Object ID | 对象ID,用于创建文档的ID |
Binary Data | 二进制数据,用于存储二进制数据 |
Code | 代码类型,用于在文档中存储JavaScript代码 |
Regular expression | 正则表达式类型,用于存储正则表达式 |
MongoDB连接
连接实例
mongodb://localhost
mongodb://fred:foobar@localhost
mongodb://fred:foobar@localhost/baz
mongodb:///example.com:27017,example2.com:27017
mongodb://localhost,localhost:27018,localhost:27019
mongodb://host1,host2,host3/?connect=direct;slaveOk=true
mongodb://localhost/?safe=true
mongodb://host1,host2,host3/?safe=true;w=2;wtimeoutMS=2000
MongoDB创建数据库
use DATABASE_NAME
use runoob
db
shows dbs
db.runoob.insert({"name":"菜鸟教程"})
MongoDB删除数据库
db.dropDatabase() #删除数据库
show dbs
use runoob
db.collection.drop() #删除集合
MongoDB创建集合
db.createCollection(name,options)
use test
db.createCollection("runoob")
show collections
db.createCollection("mycol",{capped:true,autoIndexId:true,size:6142800,max:10000})
MongoDB删除集合
db.collection.drop()
MongoDB插入文档
db.COLLECTION_NAME.insert(document)
db.COLLECTION_NAME.save(document)
db.collection.insertOne(
<document>,
{
writeConcern: <document>
}
) #用于向集合插入一个新文档
db.collection.insertMany(
[ <document 1>,<document 2>,...],
{
writeConcern:<document>,
ordered:<boolean>
}
) #插入多个值
db.col.find()
MongoDB更新文档
db.collection.update(
<query>,
<update>,
{
upsert:<boolean>,
multi:<boolean>,
writeConcern:<document>
}
)
db.col.update({'title':''})
MongoDB删除文档
db.collection.remove(
<query>,
<justOne>
)
db.collection.remove(
<query>,
{
justOne:<boolean>,
writeConcern:<document>
}
)
db.col.insert({title:'MongoDB 教程',
description:'MongoDB是一个Nosql数据库',
by:'菜鸟教程',
url:'http://www.runoob.com',
tags:['mongodb','database','Nosql'],
likes:100
})
db.col.find()
db.col.remove({'title':'MongoDB教程'})
#官方推荐
db.inventory.deleteMany({})
db.inventory.deleteMany({status:"A"})
db.inventory.deleteOne({status:"D"})
#remove()方法并不会真正释放空间
db.repairDatabase()
db.runCommand({repairDatabas:1})
MongoDB查询文档
db.collection.find(query,projection)
db.col.find().pretty()
#通过by和title键来查询菜鸟教程中MongoDB教程的数据
db.col.find({"by":"菜鸟教程","title":"MongoDBj教程")}.pretty()
# MongoDB or条件语句使用关键字$or,语法如下:
db.col.find({
$or:[
{key1:value1},{key2:value2}
]
}).pretty()
db.col.find({"likes":{$gt:50},$or:[{"by":"菜鸟教程"},{"title":"MongoDB教程"}]}).pretty()
MongoDB(>)大于操作符 - $gt
db.col.find({like:{$gt:100})
select * from col where like > 100;
db.col.find({likes:{$gte:100}})
select * from col where likes >=100;
db.col.find({like:{$lt:150}})
select * from col where likes < 150;
db.col.find(likes:{$lt:200,$gt:100})
#模糊查询
db.col.find({title:/教/})
db.col.find({title:/^教/})
db.col.find({title:/教$/})
MongoDB limit与skip方法
#读取指定数量的数据
db.COLLECTION_NAME.find().limit(NUMBER)
db.col.find({},{"title":1,_id:0}).limit(2)
#跳过指定数量的数据
db.col.find({},{"title":1,_id:0}).limit(1).skip(1)
MongoDB 排序
db.COLLECTION_NAME.find().sort({KEY:1})
db.col.find({},{"title":1,_id:0}).sort({"likes":-1})
MongoDB 索引
MongoDB使用createIndex()方法来创建索引
db.collection.createIndex(keys,options)
db.col.createIndex("title":1,"description":-1)
db.values.createIndex({open:1,close:1},{backgroud:true})
db.col.getIndexs() #集合索引大小
db.col.totalIndexes() #集合索引大小
db.col.dropIndexes() #删除集合所有索引
db.col.dropIndex("索引名称")
db.article.aggregate(
{
$project:{
_id:0,
title:1,
author:1
}
}
);
db.article.aggregate(
{
$project:{
_id:0,
title:1,
author:1
}
}
);
db.article.aggregate(
{
$skip:5
}
);
MongoDB 聚合
- 什么是复制?
- 保障数据的安全性
- 数据高可用性
- 灾难恢复
- 无需停机维护(如备份、重建索引、压缩)
- 分布式读取数据
MongoDB复制原理
mongodb复制至少需要两个节点,其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。
mongodb各个节点常见的搭配方式为:一主一从,一主多从
- 副本集特征:
- N个节点的集群
- 任何节点可作为主节点
- 自动故障转移
- 自动恢复
MongoDB副班集设置
mongod --port 20717 --dbpath "D:\set up\mongodb\data" --replSet rs0
MongoDB 分片
在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求
为什么使用分片
- 复制所有的读入操作到主节点
- 延迟的敏感数据会在主节点查询
- 单个副本集限制在12个节点
- 当请求量巨大时会出现内存不足
- 本地磁盘不足
- 垂直扩展价格昂贵
三个组件
shard:用于存储实际的数据块
Config server:mongod实例,存储整个ClusterMetadata,其中包括chunk信息
Query Routers:前端路由,客户端由此接入,且让整个集群看上去像单一数据库
MongoDB 备份与恢复
#备份
mongodb -h dbhost -d dbhome -0 dbdirectory
#恢复
mongorestore -h <hostname><:port> -d dbname <path>
MongoDB 监控
#mongostat是mongodb自带的状态监测工具
/set up/mongodb/bin>mongostat
#mongotop也是mongodb下的一个内置工具
/set up/mongodb/bin>mongotop
MongoDB java
#驱动 mongo-java-driver-3.2.2.jar
#连接数据库 (无密码)
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
public class MongoDBJDBC{
public static void main( String args[] ){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");
System.out.println("Connect to database successfully");
}catch(Exception e){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
}
#有密码登录数据库
import java.util.ArrayList;
import java.util.List;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoDatabase;
public class MongoDBJDBC {
public static void main(String[] args){
try {
//连接到MongoDB服务 如果是远程连接可以替换“localhost”为服务器所在IP地址
//ServerAddress()两个参数分别为 服务器地址 和 端口
ServerAddress serverAddress = new ServerAddress("localhost",27017);
List<ServerAddress> addrs = new ArrayList<ServerAddress>();
addrs.add(serverAddress);
//MongoCredential.createScramSha1Credential()三个参数分别为 用户名 数据库名称 密码
MongoCredential credential = MongoCredential.createScramSha1Credential("username", "databaseName", "password".toCharArray());
List<MongoCredential> credentials = new ArrayList<MongoCredential>();
credentials.add(credential);
//通过连接认证获取MongoDB连接
MongoClient mongoClient = new MongoClient(addrs,credentials);
//连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("databaseName");
System.out.println("Connect to database successfully");
} catch (Exception e) {
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
}
#创建集合
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
public class MongoDBJDBC{
public static void main( String args[] ){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");
System.out.println("Connect to database successfully");
mongoDatabase.createCollection("test");
System.out.println("集合创建成功");
}catch(Exception e){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
}
#获取集合
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
public class MongoDBJDBC{
public static void main( String args[] ){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");
System.out.println("Connect to database successfully");
MongoCollection<Document> collection = mongoDatabase.getCollection("test");
System.out.println("集合 test 选择成功");
}catch(Exception e){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
}
#插入文档
import java.util.ArrayList;
import java.util.List;
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
public class MongoDBJDBC{
public static void main( String args[] ){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");
System.out.println("Connect to database successfully");
MongoCollection<Document> collection = mongoDatabase.getCollection("test");
System.out.println("集合 test 选择成功");
//插入文档
/**
* 1. 创建文档 org.bson.Document 参数为key-value的格式
* 2. 创建文档集合List<Document>
* 3. 将文档集合插入数据库集合中 mongoCollection.insertMany(List<Document>) 插入单个文档可以用 mongoCollection.insertOne(Document)
* */
Document document = new Document("title", "MongoDB").
append("description", "database").
append("likes", 100).
append("by", "Fly");
List<Document> documents = new ArrayList<Document>();
documents.add(document);
collection.insertMany(documents);
System.out.println("文档插入成功");
}catch(Exception e){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
}
#检索所有文档
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
public class MongoDBJDBC{
public static void main( String args[] ){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");
System.out.println("Connect to database successfully");
MongoCollection<Document> collection = mongoDatabase.getCollection("test");
System.out.println("集合 test 选择成功");
//检索所有文档
/**
* 1. 获取迭代器FindIterable<Document>
* 2. 获取游标MongoCursor<Document>
* 3. 通过游标遍历检索出的文档集合
* */
FindIterable<Document> findIterable = collection.find();
MongoCursor<Document> mongoCursor = findIterable.iterator();
while(mongoCursor.hasNext()){
System.out.println(mongoCursor.next());
}
}catch(Exception e){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
}
#更新文档
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
public class MongoDBJDBC{
public static void main( String args[] ){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");
System.out.println("Connect to database successfully");
MongoCollection<Document> collection = mongoDatabase.getCollection("test");
System.out.println("集合 test 选择成功");
//更新文档 将文档中likes=100的文档修改为likes=200
collection.updateMany(Filters.eq("likes", 100), new Document("$set",new Document("likes",200)));
//检索查看结果
FindIterable<Document> findIterable = collection.find();
MongoCursor<Document> mongoCursor = findIterable.iterator();
while(mongoCursor.hasNext()){
System.out.println(mongoCursor.next());
}
}catch(Exception e){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
}
#删除第一个文档
import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
public class MongoDBJDBC{
public static void main( String args[] ){
try{
// 连接到 mongodb 服务
MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
// 连接到数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");
System.out.println("Connect to database successfully");
MongoCollection<Document> collection = mongoDatabase.getCollection("test");
System.out.println("集合 test 选择成功");
//删除符合条件的第一个文档
collection.deleteOne(Filters.eq("likes", 200));
//删除所有符合条件的文档
collection.deleteMany (Filters.eq("likes", 200));
//检索查看结果
FindIterable<Document> findIterable = collection.find();
MongoCursor<Document> mongoCursor = findIterable.iterator();
while(mongoCursor.hasNext()){
System.out.println(mongoCursor.next());
}
}catch(Exception e){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
}
}
}
高级教程
MongoDB 关系
MongoDB的关系表示多个文档之间的逻辑上的相互联系
1对1 1对多 多对多 多对1
{
"_id":ObjectId("52ffc33cd85242f436000001"),
"name": "Tom Hanks",
"contact": "987654321",
"dob": "01-01-1991"
}
{
"_id":ObjectId("52ffc4a5d85242602e000000"),
"building": "22 A, Indiana Apt",
"pincode": 123456,
"city": "Los Angeles",
"state": "California"
}
{
"_id":ObjectId("52ffc33cd85242f436000001"),
"contact": "987654321",
"dob": "01-01-1991",
"name": "Tom Benzamin",
"address": [
{
"building": "22 A, Indiana Apt",
"pincode": 123456,
"city": "Los Angeles",
"state": "California"
},
{
"building": "170 A, Acropolis Apt",
"pincode": 456789,
"city": "Chicago",
"state": "Illinois"
}]
}
{
"_id":ObjectId("52ffc33cd85242f436000001"),
"contact": "987654321",
"dob": "01-01-1991",
"name": "Tom Benzamin",
"address_ids": [
ObjectId("52ffc4a5d85242602e000000"),
ObjectId("52ffc4a5d85242602e000001")
]
}
MongoDB 覆盖索引查询
MongoDB引用有两种:
- 手动引用(Manual References)
- DBRefs
DBRef的形式:
{ $ref : , $id : , $db : }
{
"_id":ObjectId("53402597d852426020000002"),
"address": {
"$ref": "address_home",
"$id": ObjectId("534009e4d852427820000002"),
"$db": "runoob"},
"contact": "987654321",
"dob": "01-01-1991",
"name": "Tom Benzamin"
}
{
"_id" : ObjectId("534009e4d852427820000002"),
"building" : "22 A, Indiana Apt",
"pincode" : 123456,
"city" : "Los Angeles",
"state" : "California"
}
MongoDB 查询分析
MongoDB查询分析常用函数:explain()和hint()
>db.users.ensureIndex({gender:1,user_name:1})
>db.users.find({gender:"M"},{user_name:1,_id:0}).explain()
db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})
MongoDB 原子操作
mongodb不支持事务
db.books.findAndModify ( {
query: {
_id: 123456789,
available: { $gt: 0 }
},
update: {
$inc: { available: -1 },
$push: { checkout: { by: "abc", date: new Date() } }
}
} )
#原子操作常用命令
{$set : {field : value }}
#unset 删除
{$unset : { field : 1}}
#inc对文档的某个值为数字型的健进行增减
{$inc : { field : value }}
{ $push : {field : value } }
{ $pushAll : {field : value_array}}
{$pull : {field : _value } }
{ $pop : { field : 1 } }
{ $rename : { old_field_name : new_field_name } }