MongoDB是一个高性能,开源,无模式的文档型数据库,它在许多场景下可用于替代传统的关系型数据库或键/值存储方式
基础概念:
NoSQL
泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。
NoSQL的特点:
·分关系型
·分布式
·不提供ACID功能
本身常用技术特点:
·数据模型非常简单(每个记录只有单独的键
·元数据和应用数据分离
·弱一致性
其优势:
·避免不必要的复杂
对于web应用来讲,有些一致性有些多余,所以最适用于web2.0的应用场景
·高吞吐量
·高 水平扩展和低端硬件集群
·不使用关系型映射(所以使用的模型非常简单)
其劣势:
·不支持ACID (不能支持事物,但通常生产环境都是两种数据库结合)
·功能过于简单
·没有统一的数据查询模型
NoSQL数据库类别:
·键值存储
·列式数据库
·文档数据库
每一行都相当于独立的文件
·图式数据库
存放的为图,有着复杂对象关系的视图,比如在社交网站存储每个用户之间的关系的时候,通常需要用这种模式进行存储
·缓存数据库系统:不具备存储能力,完全用来提供缓存,比如Memcached、Redis
·CAP Therorem
C,A模型:保证一致性和可用性 就是传统数据库-sql数据库
C,P模型:悲观加锁机制(最终一致性 )
A,P模型:只保证可用性 和分区容忍性 比如DNS
·ACID & BASE
主要评估于系统本身基本的可用能力 软状态 以及能实现最终一致性,分布式集群中一般都使用BASE
而数据一致性模型分为以下几种:
·强一致性
无论更新操作在哪个副本上执行,之后的操作都能获得一致性的数据
·弱一致性
用户对某一数据更新需要一定的时间,将由一定的时间段处于不一致状态,在这段时间内为弱一致性
·最终一致性
数据一致性的实现技术:
·Quorum系统 NRW策略
N:总的副本数
R:完成度操作所需要读取最少副本数
W:完成写操作所需要写入最少副本数
强制一致性 R+W>N
比如 :mysql一主两从
最终一致性 R+W<=N 意味着可以只读一部分节点,写可以只写一部分节点,但是它们之间不能交互,因此不能保持一致性,在此情况下系统只能最多保证最终一致性
两段式提交协议:2PC
分为两类节点:
·协调者进程
·参与者进程
每个事物都有可能自己去写数据,并实现持久存储,而且节点之间可以任意通信
分为两个阶段:
·请求节点
·提交阶段
每个事物的参与者进程都必须提交数据,再由协调者进程进行协调后得出最终结果才能真正意义往上提交
每个请求议案,都被列为最终议案的一部分
事物协调者将请求发送于参与者使其提交事物,于是参与者统统都提交事物(这个阶段为请求)
协调者收到请求,于是再次通知两者(参与者)使其开始提交事物(提交阶段)
协调者将所有事物进行协调处理并得出最终结果(保持最终一致性)
提交失败如何处理:
如果其中以个节点出现故障(不同意提交)那么所有提交事物则全部取消提交操作
时间戳策略:
paxos:基于选举策略来选择
向量时钟
Nosql的数据存储模型:
包含了很多种不同的技术,通常能够根据不同的机制能够把他们分为不同的流派,而最简单的分裂方式就是根据数据存储模型来进行分类
流派:
·键值存储模型:(key-value存储)只能够简单存储键值模型,而且多个键值之间不能组合使用
查找迅速
数据无结构,通常指被当做字符串货二进制数据
应用场景:主要实现内容缓存,处理大量数据的高访问负载,也能用户日志系统的日志写入等做内容缓存
实例:redis, Dynamo
·列式模型:
数据按列存储,将同一列数据存放在一起(一起可能是同一节点或同一数据集中)
优点:查找迅速因为没有特别复杂的结构模型
可扩展性强
易于实现分布式
缺点:
功能相对有限(相对sql产品来讲)
其应用场景:主要用于分布式存储或分布式文件系统等
实例:Bigtable,cassandra,HBase等
·文档模型:
数据模型:与键值型模型类似,但是vaule指向结构化数据
文档每一行被作为每一文件来存放,之所以被称为文档,比如存放一个用户的信息,存放了N个键值对:姓名 年龄 性别 一一对应一个键值对,所以一个用户的信息放在这么一个组合当中,所以它在在原有键值的基础上附加了一个容器,可以将一组键值对归类成一起,组合在一起的结果被称为文档,而我们管理的时候就以文档方式来管理,但对mongodb来讲每一个文档就相当于一行,但是文档中某个键可以有多个值
优点:数据格式要求不严格,无需事先定义结构;对于文档数据库来讲不需影响前有数据,而影响后续数据
缺点:查询性能不高,缺乏统一查询语法
应用场景:主要应用于web应用 (只要不要求事物 都可以使用mongodb)
实例:mongodb等
·图式数据库模型
数据模型:图结构模型
优点:利用图结构相关算法提高性能,满足特殊场景应用需求
缺点:实现分布式稍微困难,只能应用于某种特定环境中
应用场景:社交网络、推荐系统、关系图谱
实例:Neo4J
基于文档格式(JSON或BSON半结构化数据)存储
如何保证其性能:
·采用C++研发
·支持各种常见索引,包括主索引 辅助索引等
·不支持事物,每个操作都能保证强一致性
(直接在内存完成操作而后同步到磁盘上去(延迟操作)虽然比起memcached要差那么一点,但比起mysql 或 oracle 要好太多)
·支持很好的扩展性
复制
自动sharding
有商业支持
MongoDB特性:
·支持基于文档的查询也就意味着我们的查询可以返回一个文档也可以返回一个游标去指向一个结果集,而后通过游标的切换而获取每个结果,并支持使用mapreduce能够实现强大的聚合操作;
·网格文件系统,能够存储单个大文件或海量小文件的分布文件系统,而文件是基于GridFS接口存储在mongodb当中;
·支持地理位置空间索引 (比如查找地理位置的索引);
·被生产环境广为验证过;
·支持动态查询,意味着查询方式可以根据自己的需求去编写查询语句;
·支持query pfofiling 支持查询的性能剖析 可以明确分析出来我们所编写的sql语句的性能如何并给我们做出建议如何去写sql语句性能才会更好;
·基于复制完成自动故障转移,复制结构中通常需要3个节点,其中任何节点他们2个之间可以通过选举协议来决定谁可以成为下一个主节点,并且会被自动提升为主节点;
mongodb适用场景:
·大流量网站(高并发高性能)
·适合做缓存 (因为本身就是键值存储
·高可扩展的应用场景
·适用于OBJECTS JSON 开发环境中
MongoDB数据模型
mongodb是面相集合(Collection)的数据库
数据库:无需创建数据库 直接use databasename即可 与mysql相同,但是mysql中有表的概念,一个表包含多个行,而对于mongodb来讲,则用的是“集合”
集合又由于文档组成,所以在mongodb中,每一个文档相当于一行,多个文档称为一个集合 ,而集合又相当于一个表
比如:
{
name:tom
Age:30
Gender:M
#文档中还可以嵌套文档
books:{
first:one puppet
second:tow puppet
}
}
如果想继续存放第二个用户则:
#每个对应的文档里面要自行存储字段名(key)
{
name:jerry
Age:15
Gender:F
books:{
first:one puppet
second:tow puppet
}
}
以上所有结合起来便是一个集合,而且每个文档想多加字段或修改 很容易
则继续追加即可:
{
name:jerry
Age:15
Gender:F
books:{
first:one puppet
second:tow puppet
}
Birthday:2013-01-29
}
总结:集合无需事先定义,用到什么字段直接追加即可
MongDB初步安装
RPM包下载地址,请自行选择适用的版本:
http://downloads-distro.mongodb.org/repo/redhat/os/
rpm方式安装
[root@localhost tools]# ll | grep mongo
-rw-r--r-- 1 root root 75215295 Mar 12 2014mongo-10gen-2.4.5-mongodb_1.x86_64.rpm
-rw-r--r-- 1 root root 12500030 Mar 12 2014mongo-10gen-server-2.4.5-mongodb_1.x86_64.rpm
直接安装rpm包
[root@localhost tools]# rpm -ivh mongo-10gen*.rpm
Preparing... ###########################################[100%]
1:mongo-10gen ###########################################[ 50%]
2:mongo-10gen-server ###########################################[100%]
查看配置文件
[root@localhost tools]# grep -v '^#' /etc/mongod.conf | grep -v '^$'
logpath=/var/log/mongo/mongod.log #默认日志存单该目录
logappend=true
fork = true
dbpath=/var/lib/mongo #数据文件存放路径
pidfilepath = /var/run/mongodb/mongod.pid
为了数据使用应该找一个合理的位置来存放数据,而且mongodb本来就是存放海量数据的,所以要找一个外挂式存储目录来存放数据
[root@localhost tools]# mkdir -p /mongodb/data/
[root@localhost tools]# chown -R mongod.mongod /mongodb/data/
修改配置文件
[root@localhost tools]# vim /etc/mongod.conf
修改参数:
dbpath=/mongodb/data/
启动数据库
[root@localhost tools]# /etc/init.d/mongod start
27017为服务端口 28017为管理端口,如下所示
[root@localhost tools]# netstat -lnt
Active Internet connections (only servers)
Proto Recv-Q Send-Q LocalAddress ForeignAddress State
tcp 0 0 0.0.0.0:28017 0.0.0.0:* LISTEN
tcp 0 00.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0127.0.0.1:25 0.0.0.0:* LISTEN
tcp 0 0127.0.0.1:9000 0.0.0.0:* LISTEN
tcp 0 00.0.0.0:27017 0.0.0.0:* LISTEN
tcp 0 0:::22 :::* LISTEN
访问测试:
这里会显示相关信息
使用mongo命令来连接到本机数据库中
[root@localhost tools]# mongo
MongoDB shell version: 2.4.5
connecting to: test #默认初始使用的数据库为test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
http://docs.mongodb.org/
Questions? Try the support group
http://groups.google.com/group/mongodb-user
>
如果打开一个数据库可以
show collection
show users 可以显示用户的信息
show profile 显示性能剖析,必须打开相关功能才可以
show logs 显示日志文件
MongoDB安装及CRUD操作
创建数据库:
(无需创建)
> use testdb
switched to db testdb
> show dbs
admin (empty)
local 0.078125GB
> show collections
可以看到,没有其数据库,因为真正创建数据之前 数据库是不能够被创建的
插入数据:
> db.testcoll.insert ( {name:"tom"})
> show collections
system.indexes
testcoll
#由此看到 索引是自动生成的
#查看是否存在数据:
#将集合中查找数据,空为所有
> db.testcoll.find()
{ "_id" : ObjectId("531fac302d14ad45ff3edbdd"), "name" : "tom" }
#在mongodb中,默认为集合中为每个文档中自动生成一个对应的ID,而每个ID的号码是随机的
再次插入:
> db.testcoll.insert ({name:"jerry"})
> db.testcoll.find()
{ "_id" : ObjectId("531fac302d14ad45ff3edbdd"), "name" : "tom" }
{ "_id" : ObjectId("531faced2d14ad45ff3edbde"), "name" : "jerry" }
#前缀号不同,尾号编码按顺序加1
查看状态
> db.testcoll.stats()
{
"ns" : "testdb.testcoll", #名字为testdb库下的testcoll
"count" : 2, #有2行数据
"size" : 76, #Collectionl大小是多少
"avgObjSize" : 38, #平均每个obj的大小是多少
"storageSize" : 4096, #存储时占用的空间大小
#扩展块等等-----
"numExtents" : 1,
"nindexes" : 1,
"lastExtentSize" : 4096,
"paddingFactor" : 1,
"systemFlags" : 1,
"userFlags" : 0,
"totalIndexSize" : 8176,
"indexSizes" : {
"_id_" : 8176
},
"ok" : 1
}
删除集合
> db.testcoll.drop ()
true
> show collections
system.indexes
可以看到,我们虽然清空了集合但是数据库依然在,因为数据库初始化的时候很多数据都已经被保存下来了,而且相对来说还不算小,因为它要存储日志等相关信息的
> show dbs;
admin (empty)
local 0.078125GB
testdb 0.203125GB
进入到相关目录查看存储了哪些文件
[root@localhost tools]# cd /mongodb/data/
[root@localhost data]# ll
total 294936
drwxr-xr-x 2 mongod mongod 4096 Mar 12 08:37journal #
-rw------- 1 mongod mongod 67108864 Mar 12 08:24 local.0 #local数据库
-rw------- 1 mongod mongod 16777216 Mar 12 08:24 local.ns
-rw------- 1 mongod mongod 67108864 Mar 12 08:45testdb.0 #testdb数据库
-rw------- 1 mongod mongod 134217728 Mar 12 08:37 testdb.1
-rw------- 1 mongod mongod 16777216 Mar 12 08:45testdb.ns
drwxr-xr-x 2 mongod mongod 4096 Mar 12 08:37 _tmp
MongoDB常用操作:
如何实现查询
collection名称+find方法(查询标准比如年龄大于某个数字).sort为排序默认以升序排序,如下所示
CollectionQueryCriteriaModifiler
db.User.find( {age:{ $gt:18 } } ).sort ( { age:1 } )
每个find都会返回一个游标,所以将符合条件的所有的 collection执行的字段全部返回
需要注意的是使用find查询的时候 图中只显示的是查询标准没有声明显示哪些字段,那么其将所有符合collection的字段全部打印,如果想找出符合头一个collection的字段,那么则需要使用find1方法 只查询一个
创建文档
因为支持javascript语法架构因此支持for循环:
> for(i=1;i<=100;i++)db.testcoll.insert({Name:"User"+i,Age:i,Gender:"M",preferbook:["bluebook","yellow book"]})
查看文档(库)
> db.testcoll.find()
{ "_id" : ObjectId("531fb4ce6188101d937d4fd0"),"Name" : "User1", "Age" : 1, "Gender" :"M", "preferbook" : [ "blue book", "yellow book" ] }
{ "_id" : ObjectId("531fb4ce6188101d937d4fd1"),"Name" : "User2", "Age" : 2,
#--------------------此处略--------------------------
{ "_id" : ObjectId("531fb4ce6188101d937d4fe3"),"Name" : "User20", "Age" : 20, "Gender": "M", "preferbook" : [ "blue book", "yellow book" ] }
Type "it" for more
#默认值能显示20个 需要键入it命令 来查看以下航
使用limit限定特定行数
> db.testcoll.find().limit(3)
{ "_id" : ObjectId("531fb4ce6188101d937d4fd0"),"Name" : "User1", "Age" : 1, "Gender" :"M", "preferbook" : [ "blue book", "yellow book" ] }
{ "_id" : ObjectId("531fb4ce6188101d937d4fd1"),"Name" : "User2", "Age" : 2, "Gender" :"M", "preferbook" : [ "blue book", "yellow book" ] }
{ "_id" : ObjectId("531fb4ce6188101d937d4fd2"),"Name" : "User3", "Age" : 3, "Gender" :"M", "preferbook" : [ "blue book", "yellow book" ] }
删除行
> db.testcoll.remove({Age:10})
> db.testcoll.find().limit(11)
{ "_id" : ObjectId("531fb4ce6188101d937d4fd8"),"Name" : "User9", "Age" : 9, "Gender" : "M", "preferbook" :[ "blue book", "yellow book" ] }
{ "_id" : ObjectId("531fb4ce6188101d937d4fda"),"Name" : "User11", "Age" : 11, "Gender" : "M","preferbook" : [ "blue book", "yellowbook" ] }
{ "_id" : ObjectId("531fb4ce6188101d937d4fdb"),"Name" : "User12", "Age" : 12, "Gender" : "M","preferbook" : [ "blue book", "yellowbook" ] }
删除用户名为User14的行删除
> db.testcoll.remove({Name:"User14"})
删除用户名为User12 改为32
> db.testcoll.update({Name:"User12"},{$set: {Age:32}})
查找(find)条件:
格式:db.testcoll.find”(<query>,<projection>)”
find类似于SQL语句中的SELECT语句,其中<query>相当于sql语句总的where自居,而<projection>相当于要选定的字段
如果使用find()格式中不包含<query>,那么意味着返回对应的结果的所有的文档
查找年龄大于93的用户
> db.testcoll.find({Age: {$gte:93}})
如果只想只显示用户名和姓名和年龄:
> db.testcoll.find({Age: {$gte:93}},{Name: 1, Age: 1})
#{Name: 1, #表示显示用户名
# Age: 1} #表示显示年龄
:1表示 to的意思 意思为将其显示出来
用于多个选择条件
逻辑运算
逻辑运算一般用于多个选择条件,MongoDB支持的逻辑运算如下几种:
$or 或运算
$and 与运算
$not 非运算
$nor 反运算
例:
> db.testcoll.find({$and: [{Age: {$gt 61}},{Age: {$lt: 80}}]})
元素查询(element)
如果要根据文档中是否存在某字段等条件来挑选文档,则需要用到元素运算
$exists 根据指定字段的存在性挑选文档
$mod 将指定字段的值进行取模运算,并返回其余数为指定的文档
$type 返回指定字段的值类型为指定类型的文档
例:
> db.testcoll.insert({Name: "User101",Age:101,Gender:"F", Address: "BeiJing"})
查找只有address的文档
> db.testcoll.find({Address: {$exists:true}})
{ "_id" : ObjectId("531fc4bf4b7e74e8a40e004e"),"Name" : "User101", "Age" : 101,"Gender" : "F", "Address" : "BeiJing" }
true为包含,如果改为flase则取反
更新操作
使用multi更改多个
将年龄大于80的用户的性别全部改为F
> db.testcoll.update({Age: {$gt:80}},{$set: {Gender: "F"}},{multi: ture})
删除指定字段,使用unset指定字段列表
> db.testcoll.update({Name: "User80"},{$unset: {preferbook:""}})
本文转自zuzhou 51CTO博客,原文链接:http://blog.51cto.com/yijiu/1380513