一、为什么要使用NoSQL数据库
NoSQL数据库在我的理解是一类数据库的统称(如键值存储型,文档型,列存储型等等)。
NoSQL出现的意义是啥呢?适用关系型数据库的时候就使用关系型数据库(目前大部分我们所使用的数据库均为关系型),不适用的时候也没有必要非使用关系型数据库不可,这个时候就可以考虑更加合适的数据库,比如NoSQL数据库。
至于为什么说在这里使用NoSQL数据库会更加合适呢?我们只要弄明白关系型数据库有什么优势和不足,问题就迎刃而解了。本书的5-6页、第20页以及后面均有相应的介绍,我在这里也总结一下:
⒈ 首先,关系型数据库是一项成熟的技术,发展很久了,网上几乎涵盖了所有BUG的解决办法,这对于我们来说是很重要的一点,换句话说就是用的放心;其次,是它的事务处理能力,可以保持数据的一致性,当然了,NoSQL也可以,但是应用中比较困难;最后是,它可以进行JOIN等复杂的查询,显然NoSQL是不可以的。
⒉ 那么关系型数据库的不足是什么呢?①就是它不擅长大量数据的写入,比如TB、PB级的。②呢,为了加快查询我们往往会加索引,但是之后要对表结构进行变更的话,处理起来却相当繁琐,可能会涉及到序列化的问题(对于这个问题,文档型的MongoDB数据库就有很好的解决办法,后面再提及)。③若字段不固定时:有些字段是我们在进行到项目中途的时候根据需求后加的,这种时候就容易出现表结构与程序之间不一致的问题,从而导致出错。④有些查询需要快速返回结果,这时并不是说关系型数据库查询慢,而是NoSQL数据库在这方面的性能更为突出,尤其是数据量巨大且多表查询时,优势将更为明显。
之所以说了这么多,也是请大家千万不要产生这样的误解:关系型数据库不好。
书中曾无数次的用相关语句来提醒读者:NoSQL数据库只是弥补关系型数据库的不足,在大多数的情况下我们还是要首先考虑关系型数据库的。
二、什么时候使用NoSQL数据库
如果通过第一大点的阐述大家还是比较模糊究竟什么时候使用NoSQL,那么就暂时先记住两点:
⒈ 对大量数据的写入处理时,
⒉ 简单查询需要快速返回结果时。
三、NoSQL数据库的分类
1.键值存储型(数据是以键值的形式存储的):
⑴临时型:memcached属于这种数据库,因为他把所有数据都保存在内存中,这样保存和读取的速度非常快。但是这样也有其致命缺点:当memcached停止的时候,数据就不存在了;而且由于数据都保存在内存中,所以无法操作超出内存容量的数据(超出时,旧数据会丢失)。
⑵永久型:Tokyo Tyrant、Flare、ROMA等属于这种类型的数据库。和临时性相反,所谓永久性就是“数据不会丢失”的意思。因为它是将数据保存在硬盘上,而非内存中。当然了,由于是要对硬盘进行IO,所以较之memcached性能上还是会有差距的,但数据不会丢失是它最大的优势。
⑶两者兼具:Redis属于这种数据库。它集合了临时性键值存储和永久性键值存储的优点。它的原理是首先把数据保存到内存中,在满足特定条件(默认是15分钟一次)时将数据写入到硬盘中。
2.面向文档的数据库:MongoDB、CouchDB属于这种类型。
它的特征是不需要定义表结构。但即便是不定义表结构,也可以像定义的表结构一样使用。这里体现了它较之关系型数据库的一个优势:关系型数据库为了加快查询速度需要创建索引,为了增加新的必要的字段还需要改变表结构,这期间可能会对表进行共享锁,可能会涉及到数据无法变更等问题,这些问题解决起来都是比较耗时的,而文档型的数据库恰恰弥补了这点。而且与键值存储型的数据库不同的是它可以通过更加复杂的查询条件来获取数据(当然了,事务处理和JOIN查询除外)
3.面向列的数据库:Cassandra、Hbase、HyperTable属于这种类型。
我们所通用的关系型数据库其实也可以称为面向行的数据库,那么这里所说的面向列的数据库就是和其相反的,是以列为单位来存储数据的。它的优势就是高扩展性,即使数据增加也不会降低处理速度(尤其是写入),所以它主要应用于需要处理大量数据的情况。但是由于它跟我们所经常使用的关系型数据库的存储思维有很大不同,所以应用起来十分困难。
四、详细介绍
下面就从以上各个类型中分别选取比较典型且常用的数据库,并以它们为例进行详细的说明。
1. memcached(临时性键值存储)
目前已有较多的Web服务应用到了memcached。
优势是极其快速的处理速度,因为它是将数据存在内存中,没有涉及硬盘的IO处理,这使得它能以比关系型数据库高很多的速度进行处理(可达到几万倍乃至更高)。以下两种情况其作用更是不可小窥:①有些网页需要执行一些耗费时间的SQL语句,②有些网页访问频繁,负载很大。
它不足的地方也是其致命的地方,就是它是临时性的存储,故一定不要处理重要的数据(可以把原始数据保存在其他地方,而memcached只是处理原始数据的备份或是通过原始数据计算出的结果),还有由于它的应用主要是用来缓存从关系型数据库中取出的数据,所以若是memcached一旦停止,本来要由它所处理的大量请求可能会转向关系型数据库并极容易使得后者崩溃(后面将提到的repcached可以在这方面提高memcached的可用性)。另外,它存在着只能通过指定键来读取数据这样的局限性,也就是说不能用类似于(LIKE)这样的模糊查询。
再插一嘴:为控制成本,我们应用memcached时实际上是通过多台服务器来运行,它使用的是一致性散列算法来分散数据(若不懂一致性散列原理请详情本书第23页)。
⑴ 安装过程略过(详见本书第27页)。
⑵ 启动命令:
sudo/etc/init.d/memcached start
若进程为:
$ps aux | grep memcached
Memcached –d–p 11211 –u nobody –c 1024 –m 64
则说明已经启动(11211为默认端口号,1024为最大连接数,64为最大使用内存量)。
若要增加内存的存储量,或希望改变端口号,可以通过改变 /etc/init.d/memcached的CACHESIZE和PORT项目来实现,或者直接设参数:
memcached –d –p 11211 –u nobody –c 1024–m 128
可以通过telnet来连接memcached的待机端口,来确认数据的保存和读 取状况:
$telnet localhost 11211
Trying 127.0.0.1…
Connected to localhost.localdomain(127.0.0.1).
Escape character is ‘^]’.
保存数据:
格式 set <key> <flag> <expires><byte> [换行]
<value>
例 set foo 0 10 3
bar
STORED
读取数据:
格式 get <key>
例 get foo
结果 VALUE foo 0 3
bar
END
解释:flag = 0时:不压缩 ; flag = 1 时:压缩
expires :制定数据的保存时间(设0时表示有效期无限)
byte :指定作为值保存的数据的字节数
另外,memcached还可以使用incr、delete、append、flush _all等命令
incr : 加法
delete : 删除
append : 数据末尾添加数据
flush _all : 删除memcached上的所有数据
⑶ 简单实例:
① 一台服务器时:
本书的实例是在Ruby(Ruby是上世纪90年代由日本人松本行弘开发的面向对象的脚本语言)的程序上使用memcached,而非JAVA的程序。
$KCODE=’u’
require “rubygems”
require “memcache”
server = [‘localhost:11211’] #指定要使用的memcached
option = { }
cache = MemCache.new(server,option)
#保存数据(‘#’号的作用为注释):
cache[‘key1’] = 123 #数字
cache[‘key2’] = “ABCDE” #字符串
cache[‘key3’] = %w(hoge fuga) #数组
cache[‘key4’] = { :foo => 1,:bar => “a”} #散列表
#读取数据:
pcache[‘key1’] #123
pcache[‘key2’] #”ABCDE”
pcache[‘key3’] #[“hoge”,”fuga”]
pcache[‘key4’] #{ :bar=> “a”, :foo => 1}
经确认,数字、字符串、数组、散列表等都能被正确的读取出来。经过上面的例子,可以看出在Ruby程序下使用memcache的格式为:
cache = MemCache.new([‘localhost:11211’])
cache = [‘key’] = ‘value’
p cache[‘key’]
#value
之后呢,作者举了一个使用散列表的实例,意在说明两者的相似度极高(且我发现使用散列表这个实例在本书接下来使的出现率是比较高的):
hash = {}
hash[‘key‘] = ‘value’
p hash[‘key’]
#value
看到这里我也出现了一个疑问,就在这之前保存和读取数据的格式不是用的set和get方法么,怎么这里又用到了诸如“[] = ”,这个什么意思?接下来,作者变做了详细解释:
在使用Ruby程序下的一个叫做memcache-client的程序库时,memcache-client为数据的保存和读取分别提供了两种方法:数据保存可以用set方法和 [] = 方法,数据读取可以用get和 [] 方法;当然了,这两种方法还是有点区别的:使用set方法可以自由设定expires(失效时间),但是 [] = 方法不能设定,而是使用0作为默认设定。
② 多台服务器时:
首先分别设定待机端口号(11211、11212、11213)启动3台memcached服务器:
memcached –d –p 11211 –u nobody –c 1024–m 64
memcached –d –p 11212 –u nobody –c 1024–m 64
memcached –d –p 11213 –u nobody –c 1024–m 64
要实现这个事例,请大家注意,所使用的程序库必须要支持一致性散列算法。例如此次例子中所使用的memcache-client。这样才能在增加服务器数量的同时,通过一致性散列算法来抑制缓存错误的发生,不断的扩展缓存服务器的规模。
$ KCODE=’u’
require “rubygems”
require “memcache”
require “logger” #此例在构造函数中指定了logger参数
server = [‘localhost:11211’,’localhost:11213’,’localhost:11213’]
option = { :logger =>Logger.new(STDOUT) }
cache =MemCache.new(server,option)
#保存数据:
cache[‘key1’] = 123 #数字
cache[‘key2’] = “ABCDE” #字符串
cache[‘key3’] = %w(hogefuga) #数组
cache[‘key4’] = { :foo=> 1, :bar => “a”} #散列表
#读取数据:
pcache[‘key1’] #123
pcache[‘key2’] #”ABCDE”
pcache[‘key3’] #[“hoge”,”fuga”]
pcache[‘key4’] #{ :bar=> “a”, :foo=> 1}
细心的话会发现,此例子中加入了logger参数。其作用就是可以使memcached把所有的处理都详细的记录在日志中。在开发过程中,运用好了这个东西可以很好的跟踪和掌握memcached的具体运行过程。那么,加入了logger这个参数后,效果是什么样子的呢,请详见本书的第35页。
⑷ memcached的JAVA语言用的库:spymemcached、Java memcched、javamemcachedclient、memcache-client-forjava、xmemcached、simple-spring-memcached,请大家放心,亦可使用JSON和MessagePack这样不受开发语言限制的方法将其进行序列化,使不同开发语言之间也能进行数据交互。
⑸ 相关工具:repcached
使用repcached来实现memcached的复制功能来解决前面提到的数据丢失的问题(复制过程详见本书第38-39页)。
⑹ 我们若想知道当前保存数据、内存使用量等信息,需要通过上面介绍的telent连接;或者使用memcached附带的memcached-tool脚本(script);还有就是作者在本书第42页上展示的他自己做成的memdump.rb脚本(script)。
2. TokyoTyrant(永久性键值存储)
它较之memcached 以及我们经常所使用的关系型数据库的优势除前面提到的以外:就是它还引入了数据类型的概念,可以在缓存数据库(on memory database)、散列数据库(hash database)、B-tree数据库(B-tree database)和表格数据库(table database)等数据保存方式间进行转换,因此,它可以转换为B-tree数据库进行范围查询,也可以转换为表格数据库进行复杂条件的查询;另外,它还把复制作为一项标准功能,就不用像memcached那样必须通过repcached等其他方法才能实现复制了。
再来说说它的不足吧:首先安装难度比较大。其次本书是2012年5月出版,里面提到了当时此项技术还并非很成熟,可能会遇到未知问题。
Tokyo Tyrant使用哪种数据库类型启动是通过指定其文件名后缀的方式。
缓存数据库: *
散列数据库: *.tch
B-tree数据库: *.tcb
表格数据库: *.tct
⑴ 安装过程(同样在这里我将安装过程略过,详见本书第48页)。
⑵ 启动命令: ttserver
若要启动指定文件(以hoge.tch为例): ttserverhoge.tch
默认的待机端口号是1978,并且可以再启动时通过参数来指定待机端口号、日志输出路径和数据类型等等(可参照第50页的表2-8)。
首先还是可以通过telnet来连接memcached的待机端口,来确认数据的保存和读 取状况。
$ telnet localhost 1978
Trying 127.0.0.1…
Connected to localhost.localdomain(127.0.0.1).
Escape character is ‘^]’.
由于Tokyo Tyrant支持memcached兼容协议,所以可以像memcached一样,通过set和get这样的基本命令来使用。
保存数据:
格式 set <key> <flag> <expires><byte> [换行]
<value>
例 setfoo 0 0 3
bar
STORED
读取数据:
格式 get <key>
例 getfoo
结果 VALUE foo 0 3
bar
END
然后与memcached不同的是,我们在这里可以临时停止Tokyo Tyrant,然后再次通过相同的命令ttserver hoge.tch来启动。然后再次读取数据。结果是:
getfoo
VALUEfoo 0 3
bar
END
由此可见,即使Tokyo Tyrant停止了数据也不会丢失。这就是它与memcached最大的区别。同时我们需要注意的是由于它不支持expires(失效时间),即使设定了也不起作用。
⑶ 简单实例:
① 一台服务器时:
本书作者还是在Ruby程序上使用Tokyo Tyrant,而并非JAVA 程序。由于Tokyo Tyrant支持在多种数据库类型中切换,所以在这里,列举了散列数据库和表格数据库这两种数据库类型的实例。
--散列数据库:
require‘tokyotyrant’
rdb= TokyoTyrant : :RDB.new
rdb= open(‘localhost’,1978)
#保存数据
Rdb.put(‘hoge’,’fuga’)
#也可以通过这种散列方式保存数据
#rdb[‘hoge’] = ‘fuga’
#数据读取
Prdb.get(‘hoge’) #’fuga’
#也可以通过这种散列方式读取数据
#p rdb[‘hoge’] #’fuga’
#最后不要忘记关闭数据库
rdb.close
上面这段代码是通过Tokyo Tyrant自带的协议来试用的,下面通过memcached兼容协议来试用:
require ‘rubygems’
require ‘memcache’
tt = MemCache.new([‘localhost:1978’]) #端口号发生了改变
tt[‘hoge’] = ‘fuga’
p tt[‘hope’] #’fuga’
通过memcached兼容协议,使用了与memcached相同的方法,只是需要改变一下端口号。当然了,使用memcached兼容协议,也完全可以使用memcached的客户端程序库,并通过Consistent Hashing算法来分散数据(使用memcached的时候,如果使用memcached兼容协议,就可以很容易的把数据导入Tokyo Tyrant)。
接下来我们看看除了数据的保存和读取处理,Tokyo Tyrant还提供给我们什么方法了呢?
require ‘tokyotyrant’
rdb= TokyoTyrant : :RDB.new
rdb= open(‘localhost’,1978)
rdb.put(‘hoge’,’fuga’)
rdb.put(‘foo’,’bar’)
rdb.put(‘test_1’,’data_1’)
rdb.put(‘test_2’,’data_2’)
rdb.put(‘test_3’,’data_3’)
p rdb.has_key?(‘test_1’)
#括号里面的key为键,结果返回true或false,此返回true
p rdb.has_key?(‘test_4’)
#此返回false
prdb.keys
#返回存在的键一览,为[“test_1”,”test_2”,”test_3”,”hoge”,”foo”]
prdb.fwkeys(‘test’)
#返回前方一致的键的一览,为[“test_1”,”test_2”,”test_3”]
p rdb.vanish
#删除所有数据
rdb.close
最后别忘记关闭数据库
--表格数据库
本书里作者通过一个例子来让我们了解表格数据库的使用情况。此例中,可看出表格数据库与关系型数据库是比较相似的,除了不支持JOIN和事务处理外,其他如正则表达式、合计处理、排序处理这些都能实现。
例题:创建三个人的信息数据,两个字段,为名字和生日。通过程序取出姓名以“299”结尾的数据,且按照生日降序排列。
#首先创建数据
require ‘tokyotyrant’
includeTokyoTyrant
rdb= RDBTBL.new
rdb.open(‘localhost’.1978)
rdb[‘1’]= { :name => “sasata299”, :birthday => “19830308”}
rdb[‘1’]= { :name => “tarou”, :birthday => “19801119”}
rdb[‘1’] = { :name => “hana299”, :birthday=> “19860730”}
#取值命令如下
query= RDBQRY.new(rdb)
query.addcond(“name”,RDBQRY: : QCSTREW,”299”)
query.setorder(“birthday”,RDBQRY :: QONUMDESC)
res = query.search()
#只返回键值
pres
#[“3”,”1”]
#通过get方法也可以取到具体的值
prdb.get(res[0])
prdb.get(res[1])
#{“name”=> “haha299”,”birthday” => “19860730”}
#{“name”=> “sasata299”,”birthday” => “19830308”}
#知道键的情况下也可以直接取得数据
prdb.get(‘2’)
#{“name”=> “tarou”,”birthday” => ”19801119”}
#最后不要忘记关闭数据库
rdb.close
在上面这段程序中出现了几个比较陌生的常量。具体什么意思呢?介绍几个典型的来给大家认识:
TokyoTyrant : :RDBQRY : :QCSTREQ
#字符串完全匹配查询
TokyoTyrant : :RDBQRY : :QCSTRINC
#字符串模糊查询(LIKE)
TokyoTyrant : :RDBQRY : :QCSTRBW
#字符串前方一致
TokyoTyrant : :RDBQRY : :QCSTREW
# 字符串后方一致
TokyoTyrant : :RDBQRY : :QCNUMEQ
#数值比较 ( = )
TokyoTyrant : :RDBQRY : :QCNUMGT
#数值比较 ( > )
TokyoTyrant : :RDBQRY : :QCNUMGE
#数值比较 ( >= )
TokyoTyrant : :RDBQRY : :QCNUMLT
#数值比较 ( < )
TokyoTyrant : :RDBQRY : :QCNUMLE
#数值比较 ( <= )
TokyoTyrant : :RDBQRY : :QOSTRDESC
#文字降序排列
TokyoTyrant : :RDBQRY : :QOSTRASC
#文字升序排列
TokyoTyrant : :RDBQRY : :QONUMDESC
#数值降序排列
TokyoTyrant : :RDBQRY : :QONUMASC
#数值升序排列
上面列举了一台服务器时,散列数据库和表格数据库这两种数据库类型的实例。下面来看看多台服务器时是如何的呢?
② 多台服务器时:
由于使用了memcached兼容协议,所以也可以像memcached一样使用ConsistentHashing算法来进行数据分散。下面我们来指定3个待机端口号(1978、1979、1980)来启动Tokyo Tyrant。
ttserverdata_1978.tch
ttserver–port 1979 data_1979.tch
ttserver–port 1980 data_1980.tch
#除了端口号不同之外,其他都跟memcached的使用方法相同。
$KCODE=’u’
require “rubygems”
require“memcache”
require “logger”
server = [‘localhost:1978’,’localhost:1979’,’localhost:1980’]
option = { :logger => Logger.new(STDOUT) }
cache = MemCache.new(server,option)
#保存数据:
cache[‘key1’] = 123 #数字
cache[‘key2’] = “ABCDE” #字符串
cache[‘key3’]= %w(hoge fuga) #数组
cache[‘key4’]= { :foo => 1, :bar => “a”} #散列表
#读取数据:
p cache[‘key1’] #123
p cache[‘key2’] #”ABCDE”
p cache[‘key3’] #[“hoge”,”fuga”]
p cache[‘key4’] #{:bar => “a”, :foo => 1}
⑷ TokyoTyrant的JAVA语言用的库:tokyotyrant-java
⑸ TokyoTyrant将复制处理作为一项标准功能。下面来实现一下,启动两台机器分别作为主数据库和从数据库:
#建立更新日志的保存目录
mkdir ulog_1978
mkdir ulog_1979
#主数据库的启动
ttserver-ulog ulog_1978 –sid 1 data_1978.tch
#从数据库的启动
ttserver –port 1979 – ulog ulog_1979 –sid 2 –mhostlocalhost –mport 1978 –rts rts_1979.rts data_1979.tch
复制的时候通过-ulog参数来指定更新日志文件的保存目录,然后通过从数据库来指定主数据库的主机名(-mhost)、端口号(-mport),以及用来记录复制时间点的复制时间戳文件(-rts),这样复制的准备工作就完成了。
使用telent通过1978号端口连接Tokyo Tyrant(主数据库),尝试保存数据。
$ telnet localhost 1978
Trying 127.0.0.1…
Connected to localhost.localdomain(127.0.0.1).
Escape character is ‘^]’.
set hope 0 0 4
# fuga
STORED
get hoge
# VALUE hope 0 4
# fuga
END
看到数据在主数据库中被成功保存了,读取也没有任何的问题。下面我们在从数据库中来确认一下是否复制成功吧。
$ telnet localhost 1979
Trying 127.0.0.1…
Connected to localhost.localdomain(127.0.0.1).
Escape character is ‘^]’.
get hoge
# VALUE hope 0 4
# fuga
END
看到向1979号端口的Tokyo Tyrant(从数据库)中复制数据也成功了。
⑹ 相关工具:本书介绍了两种Tokyo Tyrant的相关工具,他们是MiyazakiResistance和ActiveTokyoCabinet,它们都是对表格数据库进行的封装,能够使表格数据库更易于操作。它们具体的安装及使用的例子请详见本书59-60页。
⒊ Redis(临时性/持久性键值存储)
它兼具临时性和永久性,是介于memcached和Tokyo Tyrant之间的键值存储。
那么,为什么要使用Redis呢?
首先,通过之前的内容我们知道memcached和Tokyo Tyrant处理字符串和标准的散列数据的性能是优越的,那么处理数值和数组类型数据的效果呢。就有待考究了。
然后我们再从数据的一致性来考虑。通过memcached和Tokyo Tyrant来进行操作数组形式数据,并且要保持数据的一致性,这在实际应用中是比较困难的。为什么这么说呢,因为当memcached和Tokyo Tyrant更新数据的时候,必须完成三个处理:取得数据、变更数据、保存数据。虽然每一步只需要很短的时间,但由于都是单独的处理,所以不管怎样,这三步之间都会存在时间延迟。当多个请求同时对一个键对应的数据进行更新的时候就可能发生数据不一致的情况。而Redis则会把这样的一连串的操作定义为原子操作,即不可拆分的操作,并且提供很多的命令来保证数据的一致性。
特征:Redis通常是把数据保存在内存中,如此看来它和memcached是十分相似的;那么,已经有了memcached,Redis还有存在的价值么?答案是肯定的。memcached主要是用作关系型数据库的缓存,与关系型数据库结合使用,对简单的操作进行优化处理。与之相对,Redis本身就是作为数据存储而设计出来的,它的操作命令也达到了100多种之多。
数据快照:Redis在向硬盘写入数据的时候,提供了数据快照这样的永久化功能。再启动的时候数据快照中的内容就会被读入到内存中,恢复到上次数据快照时的状态,因此不会造成数据丢失。
⑴ 安装命令(版本2.0.4):
wget http://redis.googlecode.com/files/redis-2.0.4.tar.gz
tar zxvf redis-2.0.4.tar.gz
cd redis-2.0.4
make
sudo cpredis-server/usr/local/bin
sudo cp redis.conf/etc
⑵ 启动命令:
redis-server/etc/redis.conf
默认的待机端口号是6379。待机端口号以及数据快照等设定可以通过配置文件来完成(详情本书第72页)。
Redis也是通过telnet来进行动作确认的,其具体方法和memcached和Tokyo Tyrant略有差别:
$ telnet localhost 6379
Trying 127.0.0.1…
Connected to localhost.localdomain(127.0.0.1).
Escape character is ‘^]’.
# set <key> <byte> [换行]
# <value>
set hoge 4
fuga
# +OK
# get <key>
get hoge
$ 4
# fuga
# setex <key> <expires><byte> [换行]
# <value>
setex foo 5 3
bar
# +OK
get foo
$ 3
# bar
# 5秒时候数据消失 数据不存在的时候返回 $ -1
get foo
# $ -1
很显然,set和setex类似,但区别为setex可以使用expires(失效时间),set则不可以。
对于不同的数据类型,Redis还可以使用许多其他的命令,详见本书第76页的表2-13。
⑶ Redis的JAVA语言用的库:Jedis,JRedis。
⒋ MongoDB(面向文档的数据库)
MongoDB的优势,在开篇时已经介绍的比较详细了,这里就略过。
我们只知道它的特征是无表结构,那么,它到底是如何保存数据的呢?MongoDB在保存数据的时候会把数据和数据结构都完整地以BSON(JSON的二进制化产物)的形式保存起来,并把它作为值和特定的键进行关联。
关系型数据库中的表在面向文档数据库中称为集合(collection),关系型数据库中的记录在面向文档数据库中被称为文档(document)。
它和Redis一样,基本上是单独使用的,无需和关系型数据库配合使用;不是像memcached和Tokyo Tyrant那样是对关系型数据库弱点的补足。
⑴ 启动命令:
sudo/etc/init.d/mongodstart
启动成功后的进程:
$ps aux | grep mongodb
/usr/bin/mongod–f /etc/mongod.conf
启动时也可以设定参数来指定保存数据的目录和待机端口号等,详情本书第88页的表2-16。
memcached和Tokyo Tyrant都是通过telnet来进行动作确认的,而MongoDB提供了JavaScript的mongo shell:
$ mongo
MongoDB shell version:1.6.5
connection to:test #若不指定,一开始会连接test数据库
> show dbs #显示数据库的命令
# admin
# local
> show collections #显示collection的命令
此时test数据库并不存在,只存在admin数据库和local数据库。与关系型数据库的表对应的collection中也什么都没有。接下来看看如何保存数据吧:
>db.users.save({ name:”sasata299”}) #写入数据
>db.users.find()
#{ “_id”:ObjectId(“4d4d3e13d8bca4f2ba32ba4f”),”name”:“sasata299”}
> show dbs
# users
# system.indexes
这个test数据库本身并不存在,数据依然被准确的创建出来了。另外,大家在上面是否注意到MongoDB包含一个称为_id的值。它是用来识别自身的12字节的唯一存在的值。这个值如果不指定的话会自动生成,在collection中是唯一存在的。类似于关系型数据库中生成的连续ID。
⑵ 在多台服务器上使用:
MongoDB与memcached和Tokyo Tyrant以及Redis都不同,它是通过碎片算法(sharding)来进行数据分散的。它的原理是根据user_id的范围把数据分散到不同的服务器上的(从某个值到某个值分配到服务器1上,把某个值到某个值分配到服务器2上)。这是一种范围分割,是以范围为单位把数据集中分散到某一台服务器上,因此它比较擅长进行范围查询。
⑶ MongoDB的JAVA语言用的库是:Morphia。