免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 14114 | 回复: 8
打印 上一主题 下一主题

多个字段组成的联合字段的主键 在mongo 里如何表达 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-07-26 15:16 |只看该作者 |倒序浏览
本帖最后由 liyihongcug 于 2011-07-26 15:24 编辑

研究 mongodb, 可惜他的主键是系统自动生成的 。  我的当前应用是 当前业务表id + mesId(有一个中间表的id) 是2个字段组合而成一个主键,

羡慕mongodb的速度, 现在把mongodb不支持多表join的问题排开,先讨论这个问题

多个字段组成的联合字段的主键 在mongo 里如何表达?  (当前的主表都是多字段组合成一个pk, 有的甚至3个字段 组合成一个pk


(如果不能这样通过另外的方式解决  那么我的当前应用整个业务体系架构将要被更改)

论坛徽章:
0
2 [报告]
发表于 2011-08-03 16:17 |只看该作者
本帖最后由 liyihongcug 于 2011-08-04 16:18 编辑

http://www.iteye.com/topic/757301
直接 save({_id: "http://shaunli.com/"}) 可以避免系统自动生成 ObjectId

补充 :
MongoDB创建数据库,MongoDB创建数据库,MongoDB创建数据库,MongoDB创建数据库



MongoDB创建数据库完全可以使用use



如下:

use mydb;


这样就创建了一个数据库。

这一步很重要如果什么都不操作离开的话 这个库就会被系统删除。



验证-------------------------------

然后使用插入语句:

db.usr.insert({'name':'tompig'});

在使用下列命令查看

show collections;  ---查看‘表’
操作历史
> use mydb
switched to db mydb
> help
        db.help()                    help on db methods
        db.mycoll.help()             help on collection methods
        rs.help()                    help on replica set methods
        help connect                 connecting to a db help
        help admin                   administrative help
        help misc                    misc things to know
        help mr                      mapreduce help

        show dbs                     show database names
        show collections             show collections in current database
        show users                   show users in current database
        show profile                 show most recent system.profile entries with time >= 1ms
        use <db_name>                set current database
        db.foo.find()                list objects in collection foo
        db.foo.find( { a : 1 } )     list objects in foo where a == 1
        it                           result of the last line evaluated; use to further iterate
        DBQuery.shellBatchSize = x   set default number of items to display on shell
        exit                         quit the mongo shell
> show dbs
admin   (empty)
local   (empty)
test    0.0625GB
> db.usr.insert({'name':'tompig'});
> show collections;
system.indexes
usr
> show dbs                        
admin   (empty)
local   (empty)
mydb    0.0625GB
test    0.0625GB



删除数据库:
> use test
switched to db test
> db.foo.save({name:'asdfdsf'})
> show dbs
admin
local
test
> db
test
> db.dropDatabase()
{ "dropped" : "test", "ok" : 1 }
> show dbs
admin
local
>

删除集合:
> use test
switched to db test
> db.foo.save({name:'sdfdsf'})
> show collections
foo
system.indexes
> db.foo.drop()
true
> show collections
system.indexes
>


  mongodb由C++写就,其名字来自humongous这个单词的中间部分,从名字可见其野心所在就是海量数据的处理。关于它的一个最简洁描述为:scalable, high-performance, open source, schema-free, document-oriented database。MongoDB的主要目标是在键/值存储方式(提供了高性能和高度伸缩性)以及传统的RDBMS系统(丰富的功能)架起一座桥梁,集两者的优势于一身。

   

安装及使用:

首先在Ubuntu上安装MongoDB。

下载MongoDB, 现在最新的生产版本1.7.0

1.                   解压文件.

$ tar -xvf mongodb-linux-i686-1.4.3.tgz

2.                  为MongoDB创建数据目录,默认情况下它将数据存储在/data/db

$ sudo mkdir -p /data/db/

$ sudo chown `id -u` /data/db

3.                  启动MongoDB服务.

$ cd mongodb-linux-i686-1.4.3/bin

$ ./mongod

4.                  打开另一个终端,并确保你在MongoDB的bin目录,输入如下命令.

$ ./mongo
一些概念

一个mongod服务可以有建立多个数据库,每个数据库可以有多张表,这里的表名叫collection,每个collection可以存放多个文档(document),每个文档都以BSON(binary json)的形式存放于硬盘中,因此可以存储比较复杂的数据类型。它是以单文档为单位存储的,你可以任意给一个或一批文档新增或删除字段,而不会对其它文档造成影响,这就是所谓的schema-free,这也是文档型数据库最主要的优点。跟一般的key-value数据库不一样的是,它的value中存储了结构信息,所以你又可以像关系型数据库那样对某些域进行读写、统计等操作。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。Mongo还可以解决海量数据的查询效率,根据官方文档,当数据量达到50GB以上数据时,Mongo数据库访问速度是MySQL10 倍以上。

BSON

BSON是Binary JSON 的简称,是一个JSON文档对象的二进制编码格式。BSON同JSON一样支持往其它文档对象和数组中再插入文档对象和数组,同时扩展了JSON的数据类型。如:BSON有Date类型和BinDate类型。

BSON被比作二进制的交换格式,如同Protocol Buffers,但BSON比它更“schema-less”,非常好的灵活性但空间占用稍微大一点。

BSON有以下三个特点:

1.  轻量级

2.  跨平台

3.  效率高

命名空间

MongoDB存储BSON对象到collections,这一系列的数据库名和collection名被称为一个命名空间。如同:java.util.List;用来管理数据库中的数据。
索引

mongodb可以对某个字段建立索引,可以建立组合索引、唯一索引,也可以删除索引,建立索引就意味着增加空间开销。默认情况下每个表都会有一个唯一索引:_id,如果插入数据时没有指定_id,服务会自动生成一个_id,为了充分利用已有索引,减少空间开销,最好是自己指定一个unique的key为_id,通常用对象的ID比较合适,比如商品的ID。



shell操作数据库:



   1.  超级用户相关:

         1. #进入数据库admin

use admin

         2. #增加或修改用户密码

          db.addUser('name','pwd')

         3. #查看用户列表

          db.system.users.find()

         4. #用户认证

          db.auth('name','pwd')

         5. #删除用户

          db.removeUser('name')

         6. #查看所有用户

          show users

         7. #查看所有数据库

          show dbs

         8. #查看所有的collection

          show collections

         9. #查看各collection的状态

          db.printCollectionStats()

        10. #查看主从复制状态

          db.printReplicationInfo()

        11. #修复数据库

          db.repairDatabase()

        12. #设置记录profiling,0=off 1=slow 2=all

          db.setProfilingLevel(1)

        13. #查看profiling

          show profile

        14. #拷贝数据库

          db.copyDatabase('mail_addr','mail_addr_tmp')

        15. #删除collection

          db.mail_addr.drop()

        16. #删除当前的数据库

          db.dropDatabase()

      

   2. 增删改

         1. #存储嵌套的对象

db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})



         2. #存储数组对象

db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})



         3. #根据query条件修改,如果不存在则插入,允许修改多条记录

            db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)

         4. #删除yy=5的记录

            db.foo.remove({'yy':5})

         5. #删除所有的记录

            db.foo.remove()



   3. 索引

         1. #增加索引:1(ascending),-1(descending)

         2. db.foo.ensureIndex({firstname: 1, lastname: 1}, {unique: true});

         3. #索引子对象

         4. db.user_addr.ensureIndex({'Al.Em': 1})

         5. #查看索引信息

         6. db.foo.getIndexes()

         7. db.foo.getIndexKeys()

         8. #根据索引名删除索引

         9. db.user_addr.dropIndex('Al.Em_1')



   4. 查询

         1. #查找所有

        2. db.foo.find()

        3. #查找一条记录

        4. db.foo.findOne()

        5. #根据条件检索10条记录

        6. db.foo.find({'msg':'Hello 1'}).limit(10)

        7. #sort排序

        8. db.deliver_status.find({'From':'ixigua@sina.com'}).sort({'Dt',-1})

         9. db.deliver_status.find().sort({'Ct':-1}).limit(1)

        10. #count操作

        11. db.user_addr.count()

        12. #distinct操作,查询指定列,去重复

        13. db.foo.distinct('msg')

        14. #”>=”操作

        15. db.foo.find({"timestamp": {"$gte" : 2}})

        16. #子对象的查找

        17. db.foo.find({'address.city':'beijing'})

   5. 管理

         1. #查看collection数据的大小

         2. db.deliver_status.dataSize()

         3. #查看colleciont状态

         4. db.deliver_status.stats()

         5. #查询所有索引的大小

         6. db.deliver_status.totalIndexSize()



5.  advanced queries:高级查询


条件操作符
$gt : >
$lt : <
$gte: >=
$lte: <=
$ne : !=、<>
$in : in
$nin: not in
$all: all
$not: 反匹配(1.3.3及以上版本)

查询 name <> "bruce" and age >= 18 的数据
db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});

查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});

查询 age in (20,22,24,26) 的数据
db.users.find({age: {$in: [20,22,24,26]}});

查询 age取模10等于0 的数据
db.users.find('this.age % 10 == 0');
或者
db.users.find({age : {$mod : [10, 0]}});

匹配所有
db.users.find({favorite_number : {$all : [6, 8]}});
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }

查询不匹配name=B*带头的记录
db.users.find({name: {$not: /^B.*/}});
查询 age取模10不等于0 的数据
db.users.find({age : {$not: {$mod : [10, 0]}}});

#返回部分字段
选择返回age和_id字段(_id字段总是会被返回)
db.users.find({}, {age:1});
db.users.find({}, {age:3});
db.users.find({}, {age:true});
db.users.find({ name : "bruce" }, {age:1});
0为false, 非0为true

选择返回age、address和_id字段
db.users.find({ name : "bruce" }, {age:1, address:1});

排除返回age、address和_id字段
db.users.find({}, {age:0, address:false});
db.users.find({ name : "bruce" }, {age:0, address:false});

数组元素个数判断
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
匹配db.users.find({favorite_number: {$size: 3}});
不匹配db.users.find({favorite_number: {$size: 2}});

$exists判断字段是否存在
查询所有存在name字段的记录
db.users.find({name: {$exists: true}});
查询所有不存在phone字段的记录
db.users.find({phone: {$exists: false}});

$type判断字段类型
查询所有name字段是字符类型的
db.users.find({name: {$type: 2}});
查询所有age字段是整型的
db.users.find({age: {$type: 16}});

对于字符字段,可以使用正则表达式
查询以字母b或者B带头的所有记录
db.users.find({name: /^b.*/i});

$elemMatch(1.3.1及以上版本)
为数组的字段中匹配其中某个元素

Javascript查询和$where查询
查询 age > 18 的记录,以下查询都一样
db.users.find({age: {$gt: 18}});
db.users.find({$where: "this.age > 18"});
db.users.find("this.age > 18");
f = function() {return this.age > 18} db.users.find(f);

排序sort()
以年龄升序asc
db.users.find().sort({age: 1});
以年龄降序desc
db.users.find().sort({age: -1});

限制返回记录数量limit()
返回5条记录
db.users.find().limit(5);
返回3条记录并打印信息
db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});
结果
my age is 18
my age is 19
my age is 20

限制返回记录的开始点skip()
从第3条记录开始,返回5条记录(limit 3, 5)
db.users.find().skip(3).limit(5);

查询记录条数count()
db.users.find().count();
db.users.find({age:18}).count();
以下返回的不是5,而是user表中所有的记录数量
db.users.find().skip(10).limit(5).count();
如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
db.users.find().skip(10).limit(5).count(true);

分组group()
假设test表只有以下一条数据
{ domain: "www.mongodb.org"
, invoked_at: {d:"2009-11-03", t:"17:14:05"}
, response_time: 0.05
, http_action: "GET /display/DOCS/Aggregation"
}
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
db.test.group(
{ cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
, key: {http_action: true}
, initial: {count: 0, total_time:0}
, reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
, finalize: function(out){ out.avg_time = out.total_time / out.count }
} );

[
{
"http_action" : "GET /display/DOCS/Aggregation",
"count" : 1,
"total_time" : 0.05,
"avg_time" : 0.05
}
]



Java 应用示例

要使用Java操作MongoDB的话,要到官方网站下载一个驱动包,把包导入后,可以尝试来操作了(记得一定要开着服务器)

首先介绍一下比较常用的几个类

Mongo:连接服务器,执行一些数据库操作的选项,如新建立一个数据库等

DB:对应一个数据库,可以用来建立集合等操作

DBCollection:对应一个集合(类似表),可能是我们用得最多的,可以添加删除记录等

DBObjec:接口和BasicDBObject对象:表示一个具体的记录,BasicDBObject实现了DBObject,因为是key-value的数据结构,所以用起来其实和HashMap是基本一致的

DBCursor:用来遍历取得的数据,实现了Iterable和Iterator

接下来实际的操作一下,代码如下:

import java.net.UnknownHostException;

import java.util.List;

import java.util.Set;

import com.mongodb.BasicDBObject;

import com.mongodb.DB;

import com.mongodb.DBCollection;

import com.mongodb.DBCursor;

import com.mongodb.DBObject;

import com.mongodb.Mongo;

import com.mongodb.MongoException;

public class MongoDbTest {

  public static void main(String[] args) throws UnknownHostException, MongoException {

    //Mongo m = new Mongo();

//Mongo m = new Mongo("localhost");

//获得数据库服务

Mongo m = new Mongo("localhost", 27017);

//得到数据库mytest

DB db = m.getDB("mytest");

//得到mytest数据库下所有表名

    Set<String> colls = db.getCollectionNames();

    for (String s : colls) {

        System.out.println(s);

}

//得到testCollection表

DBCollection coll = db.getCollection("testCollection");

//new 一个BasicDBObject对象doc

BasicDBObject doc = new BasicDBObject();

//赋值

    doc.put("name", "MongoDB");

    doc.put("type", "database");

doc.put("count", 1);

//又new 一个BasicDBObject对象info

    BasicDBObject info = new BasicDBObject();

    info.put("x", 203);

info.put("y", 102);

//把info放入doc

doc.put("info", info);

//向testCollection表中插入一条数据

coll.insert(doc);

//查询一条数据

    DBObject myDoc = coll.findOne();

    System.out.println(myDoc);

   

    //循环插入100条数据到testCollection

    for (int i=0; i < 100; i++) {

      coll.insert(new BasicDBObject().append("i", i));

    }

   

   

    //Counting Documents in A Collection

    System.out.println(coll.getCount());

   

    //Using a Cursor to Get All the Documents

    DBCursor cur = coll.find();

    while(cur.hasNext()) {

http://yongtree.iteye.com/blog/890510
每个MongoDB的document都有一个_id字段作为它的第一个属性,这个值通常是一个BSON对象id,因此,这个id对于集合中的每个成员都是唯一的,如果用户插入一个document没有提供一个id,数据库将自动生成一个id,并存储在_id字段。   
   The BSON ObjectId Datatype   
一个BSON ObjectID是由12个字节组成:4字节时间+3字节机器id+2字节进程id+3字节的数字
{ "_id" : ObjectId("4c691e72ed2a47b462dfa806") }


有时候我们的应用中需要自增长的数字型主键,MongoDB在这方面并没有给我们提供支持,我们需要加以改造,使其具有自增长主键生成的功能。此次的功能改造,依赖的是morphia开源项目(MongoDB在java语言上的ORM实现,http://code.google.com/p/morphia /),直接上代码吧。


首先定义一个保存各个 collection的主键增量值的系统配置collection:StoredSeqence
java 代码

   1. /**  
   2.  * MongoDB自增长主键维护队列,类似于MSSQL,Oracle维护主键的方式  
   3.  *   
   4.  * @author yongtree  
   5.  * @date 2011-1-17 下午06:58:05  
   6.  * @version 1.0  
   7.  */  
   8. @Entity(noClassnameStored=true)   
   9. public class StoredSeqence implements Serializable {   
  10.   
  11.     private static final long serialVersionUID = 1L;   
  12.   
  13.     @Id  
  14.     String collName;   
  15.   
  16.     Long value;   
  17.        
  18.   
  19.     public StoredSeqence(){   
  20.            
  21.     }   
  22.        
  23.     public StoredSeqence(String collName) {   
  24.         this.collName = collName;   
  25.     }   
  26.   
  27.     public Long getValue() {   
  28.         return value;   
  29.     }   
  30.   
  31.     public void setValue(Long value) {   
  32.         this.value = value;   
  33.     }   
  34.   
  35.     public String getCollName() {   
  36.         return collName;   
  37.     }   
  38.   
  39.     public void setCollName(String collName) {   
  40.         this.collName = collName;   
  41.     }   
  42.   
  43.        
  44.   
  45.        
  46. }   

然后定义一个实体的基类,在基类中处理主键生成。
java 代码

   1. /**  
   2.  * 自增长数字类型主键的Mongo实体  
   3.  *   
   4.  * @author yongtree  
   5.  * @date 2011-1-17 下午04:11:04  
   6.  * @version 1.0  
   7.  */  
   8. public abstract class LongPKMongoEO extends BaseMongoEO {   
   9.   
  10.     @Id  
  11.     Long _id;   
  12.   
  13.     @Transient  
  14.     protected Datastore ds;   
  15.        
  16.        
  17.   
  18.     public void setDs(Datastore ds) {   
  19.         this.ds = ds;   
  20.     }   
  21.   
  22.     @PrePersist  
  23.     void prePersist() {   
  24.            
  25.         //自增性主键的处理   
  26.            
  27.         if (_id == null) {   
  28.             String collName = ds.getCollection(getClass()).getName();   
  29.             Query<StoredSeqence> q = ds.find(StoredSeqence.class, "_id",   
  30.                     collName);   
  31.             StoredSeqence ss = q.get();   
  32.             if(ss==null){//不存在该实体的注册,则新创建一个   
  33.                 ss = new StoredSeqence(collName);   
  34.                 ss.setValue(1l);   
  35.             }else{   
  36.                 ss.setValue(ss.getValue()+1);   
  37.             }   
  38.             ds.save(ss);   
  39.             _id=ss.value;   
  40.         }   
  41.     }   
  42.   
  43.     public Long getId() {   
  44.         return _id;   
  45.     }   
  46.   
  47. }  



这样自增长主键的生成的主要功能基本上已经完成了,具体如何使用,接下来将根据实际的项目再做介绍,请继续关注我的博客。

论坛徽章:
0
3 [报告]
发表于 2011-08-04 14:02 |只看该作者
使用组合字段的 唯一性索引 。 这个功能比想象的要强大 、
MongoDB 提供了多样性的索引支持,索引信息被保存在system.indexes 中,且默认总是为_id
创建索引,它的索引使用基本和MySQL 等关系型数据库一样。其实可以这样说说,索引是
凌驾于数据存储系统之上的另一层系统,所以各种结构迥异的存储都有相同或相似的索引实
现及使用接口并不足为奇。基础索引
在字段age 上创建索引,1(升序);-1(降序)
> db.t3.ensureIndex({age:1})
> db.t3.getIndexes();
[
{
"name" : "_id_",
"ns" : "test.t3",
"key" : {
"_id" : 1
},
"v" : 0
},
{
"_id" : ObjectId("4fb906da0be632163d0839fe"),
"ns" : "test.t3",
"key" : {
"age" : 1
},
"name" : "age_1",
"v" : 0
}
]
>
上例显示出来的一共有2 个索引,其中_id 是创建表的时候自动创建的索引,此索引是不能
够删除的。
当系统已



当系统已有大量数据时,创建索引就是个非常耗时的活,我们可以在后台执行,只需指定
“backgroud:true”即可。
> db.t3.ensureIndex({age:1} , {backgroud:true})


文档索引
索引可以任何类型的字段,甚至文档
db.factories.insert( { name: "wwl", addr: { city: "Beijing", state: "BJ" } } );
//在addr 列上创建索引
db.factories.ensureIndex( { addr : 1 } );
//下面这个查询将会用到我们刚刚建立的索引
db.factories.find( { addr: { city: "Beijing", state: "BJ" } } );
//但是下面这个查询将不会用到索引,因为查询的顺序跟索引建立的顺序不一样
db.factories.find( { addr: { state: "BJ" , city: "Beijing"} } );
16.3 组


组合索引
跟其它数据库产品一样,MongoDB 也是有组合索引的,下面我们将在addr.city 和addr.state
上建立组合索引。当创建组合索引时,字段后面的1 表示升序,-1 表示降序,是用1 还是
用-1 主要是跟排序的时候或指定范围内查询 的时候有关的。
db.factories.ensureIndex( { "addr.city" : 1, "addr.state" : 1 } );
// 下面的查询都用到了这个索引
db.factories.find( { "addr.city" : "Beijing", "addr.state" : "BJ" } );
db.factories.find( { "addr.city" : "Beijing" } );
db.factories.find().sort( { "addr.city" : 1, "addr.state" : 1 } );
db.factories.find().sort( { "addr.city" : 1 } )

唯一索引
只需在ensureIndex 命令中指定”unique:true”即可创建唯一索引。例如,往表t4 中插入2 条
记录
db.t4.insert({firstname: "wang", lastname: "wenlong"});
db.t4.insert({firstname: "wang", lastname: "wenlong"});
在t4 表中建立唯一索引
> db.t4.ensureIndex({firstname: 1, lastname: 1}, {unique: true});
E11000 duplicate key error index: test.t4.$firstname_1_lastname_1 dup key: { : "wang", :
"wenlong" }
可以看到,当建唯一索引时,系统报了“表里有重复值”的错,具体原因就是因为表中有2
条一模一模的数据,所以建立不了唯一索引

强制使用索引
hint 命令可以强制使用某个索引。
> db.t5.insert({name: "wangwenlong",age: 20})
> db.t5.ensureIndex({name:1, age:1})
> db.t5.find({age:{$lt:30}}).explain()
{
"cursor" : "BasicCursor",
"nscanned" : 1,
"nscannedObjects" : 1,
"n" : 1,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : { --并没有用到索引
}
}
> db.t5.find({age:{$lt:30}}).hint({name:1, age:1}).explain() --强制使用索引
{
"cursor" : "BtreeCursor name_1_age_1",
"nscanned" : 1,
"nscannedObjects" : 1,
"n" : 1,
"millis" : 1,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : { --被强制使用索引了
"name" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"age" : [

54 / 91
[
-1.7976931348623157e+308,
30
]
]
}
}
>

删除索引
删除索引分为删除某张表的所有索引和删除某张表的某个索引,具体如下:
//删除t3 表中的所有索引
db.t3.dropIndexes()
//删除t4 表中的firstname 索引
db.t4.dropIndex({firstname: 1})

论坛徽章:
0
4 [报告]
发表于 2011-08-04 14:15 |只看该作者
本帖最后由 liyihongcug 于 2011-08-04 15:34 编辑

http://blogs.ejb.cc/archives/227NoSQL特点
1、 它可以处理超大量的数据
2、 它运行在便宜的PC服务器集群上
PC 集群扩充起来非常方便并且成本很低,避免了传统商业数据库“sharding”操作的复杂性
和成本。
3、 它击碎了性能瓶颈
NoSQL 的支持者称,通过NoSQL 架构可以省去将Web 或Java 应用和数据转换成SQL 格式的
时间,执行速度变得更快。
“SQL 并非适用于所有的程序代码”,对于那些繁重的重复操作的数据,SQL 值得花钱。但
是当数据库结构非常简单时,SQL 可能没有太大用处。
4、 它没有过多的操作
虽然NoSQL 的支持者也承认关系型数据库提供了无可比拟的功能集合,而且在数据完整性
上也发挥绝对稳定,他们同时也表示,企业的具体需求可能没有那么复杂。
5、 它的支持者源于社区
因为NoSQL 项目都是开源的,因此它们缺乏供应商提供的正式支持。这一点它们与大多数
开源项目一样,不得不从社区中寻求支持。
NoSQL 发展至今,出现了好几种非关系性数据库, 以NoSQL 中目前表现最好的
MongoDB  。

功能测试

j = { name : "ray_linn" };
{ "name" : "ray_linn" }
> t = { x : 3 };
{ "x" : 3 }
> db.things.save(j);
> db.things.save(t);
> db.things.find();
{ "_id" : ObjectId("4e3a416156994ac1a0aa610e"), "name" : "ray_linn" }
{ "_id" : ObjectId("4e3a416556994ac1a0aa610f"), "x" : 3 }
> for (var i = 1; i <= 20; i++) db.things.save({x : 4, j : i});----------------------------请注意 这里“字段名” 必须是{} 函数是()
> db.things.find();                                            
{ "_id" : ObjectId("4e3a416156994ac1a0aa610e"), "name" : "ray_linn" }
{ "_id" : ObjectId("4e3a416556994ac1a0aa610f"), "x" : 3 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6110"), "x" : 4, "j" : 1 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6111"), "x" : 4, "j" : 2 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6112"), "x" : 4, "j" : 3 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6113"), "x" : 4, "j" : 4 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6114"), "x" : 4, "j" : 5 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6115"), "x" : 4, "j" : 6 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6116"), "x" : 4, "j" : 7 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6117"), "x" : 4, "j" : 8 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6118"), "x" : 4, "j" : 9 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6119"), "x" : 4, "j" : 10 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611a"), "x" : 4, "j" : 11 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611b"), "x" : 4, "j" : 12 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611c"), "x" : 4, "j" : 13 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611d"), "x" : 4, "j" : 14 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611e"), "x" : 4, "j" : 15 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611f"), "x" : 4, "j" : 16 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6120"), "x" : 4, "j" : 17 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6121"), "x" : 4, "j" : 18 }
has more
> var cursor = db.things.find();                                                                                                   
> while (cursor.hasNext()) printjson(cursor.next());----------------------------------------------------------使用游标 while循环
{ "_id" : ObjectId("4e3a416156994ac1a0aa610e"), "name" : "ray_linn" }
{ "_id" : ObjectId("4e3a416556994ac1a0aa610f"), "x" : 3 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6110"), "x" : 4, "j" : 1 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6111"), "x" : 4, "j" : 2 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6112"), "x" : 4, "j" : 3 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6113"), "x" : 4, "j" : 4 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6114"), "x" : 4, "j" : 5 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6115"), "x" : 4, "j" : 6 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6116"), "x" : 4, "j" : 7 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6117"), "x" : 4, "j" : 8 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6118"), "x" : 4, "j" : 9 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6119"), "x" : 4, "j" : 10 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611a"), "x" : 4, "j" : 11 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611b"), "x" : 4, "j" : 12 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611c"), "x" : 4, "j" : 13 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611d"), "x" : 4, "j" : 14 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611e"), "x" : 4, "j" : 15 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611f"), "x" : 4, "j" : 16 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6120"), "x" : 4, "j" : 17 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6121"), "x" : 4, "j" : 18 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6122"), "x" : 4, "j" : 19 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6123"), "x" : 4, "j" : 20 }
> db.things.find().forEach(printjson);--------------------------------------------------------------------使用forEach  mongo区分大小写 如果错误哦会提示
{ "_id" : ObjectId("4e3a416156994ac1a0aa610e"), "name" : "ray_linn" }
{ "_id" : ObjectId("4e3a416556994ac1a0aa610f"), "x" : 3 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6110"), "x" : 4, "j" : 1 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6111"), "x" : 4, "j" : 2 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6112"), "x" : 4, "j" : 3 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6113"), "x" : 4, "j" : 4 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6114"), "x" : 4, "j" : 5 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6115"), "x" : 4, "j" : 6 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6116"), "x" : 4, "j" : 7 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6117"), "x" : 4, "j" : 8 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6118"), "x" : 4, "j" : 9 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6119"), "x" : 4, "j" : 10 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611a"), "x" : 4, "j" : 11 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611b"), "x" : 4, "j" : 12 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611c"), "x" : 4, "j" : 13 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611d"), "x" : 4, "j" : 14 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611e"), "x" : 4, "j" : 15 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa611f"), "x" : 4, "j" : 16 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6120"), "x" : 4, "j" : 17 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6121"), "x" : 4, "j" : 18 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6122"), "x" : 4, "j" : 19 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6123"), "x" : 4, "j" : 20 }
> var cursor = db.things.find();                                                                                                   
> printjson(cursor[4]);         --------------------------------------------------------------------- 游标数组应用
{ "_id" : ObjectId("4e3a437956994ac1a0aa6112"), "x" : 4, "j" : 3 }


> db.things.find({name:"ray_linn"}).forEach(printjson); -----------------------------------相当于 select * from a where a='d'
{ "_id" : ObjectId("4e3a416156994ac1a0aa610e"), "name" : "ray_linn" }
> db.things.find({j:"19"}).forEach(printjson);         
> db.things.find({j:19}).forEach(printjson);  
{ "_id" : ObjectId("4e3a437956994ac1a0aa6122"), "x" : 4, "j" : 19 }
--------------------------------------------注意整型是不要""  这里多个字段 。如果只显示某个字段 可以让 db.things.find({x:4}, {j:true}).forEach(printjson);                                                                           
> db.things.find({x:4,j:19}).forEach(printjson);
{ "_id" : ObjectId("4e3a437956994ac1a0aa6122"), "x" : 4, "j" : 19 }
> printjson(db.things.findOne({name:"mongo"});                                                                                    
...
... exit;
... ^C-----------------------------------------------------------------输入错误的提示信息
> printjson(db.things.findOne({name:"ray_linn"}));        相当于mysql 的 limit 1
{ "_id" : ObjectId("4e3a416156994ac1a0aa610e"), "name" : "ray_linn" }
> db.things.find().limit(3);
{ "_id" : ObjectId("4e3a416156994ac1a0aa610e"), "name" : "ray_linn" }
{ "_id" : ObjectId("4e3a416556994ac1a0aa610f"), "x" : 3 }
{ "_id" : ObjectId("4e3a437956994ac1a0aa6110"), "x" : 4, "j" : 1 }
> show collections;
system.indexes
things
usr
> printjson                                                                                                                        
function (x) {
    print(tojson(x));
}
1

补充重要的一点   这个是自己插入主键
使用游标时候请注意占用内存的问题, 特别是很大的游标对象, 有可能会内存溢出. 所以应
该用迭代的方式来输出. 下面的示例则是把游标转换成真实的数组类型:
> var arr = db.things.find().toArray();
> arr[5];
{ "_id" : ObjectId("4c220a42f3924d31102bd859"), "x" : 4, "j" : 4 }
请注意这些特性只是在MongoDB shell 里使用, 而不是所有的其他应用程序驱动都支持.
MongoDB 游标对象不是没有快照,如果有其他用户在集合里第一次或者最后一次调用
next(), 你可能得不到游标里的数据. 所以要明确的锁定你要查询的游标
db.things.insert({_id:3, name:"Bill_new", age:55})
db.things.update({name:"mongo"},{$set:{name:"mongo_new"}});
db.things.remove({name:"mongo_new"});
MongoVUE
主页:http://www.mongovue.com/
一个桌面程序,提供了对MongoDB 数据库的基本操作,如查看、查询、更新、删除等,简
单易用,但是功能还比较弱,以后发展应该不错

论坛徽章:
0
5 [报告]
发表于 2011-08-04 19:25 |只看该作者
本帖最后由 liyihongcug 于 2011-08-04 20:10 编辑

提高 MongoDB 数据库安全有几个方面:
 绑定IP 内网地址访问MongoDB 服务
 设置监听端口
 使用用户名和口令登录
1 绑定IP内网地址访问MongoDB服务
MongoDB 可以限制只允许某一特定IP 来访问,只要在启动时加一个参数bind_ip 即可,如
下:
服务端限制只有192.168.1.103 这个IP 可以访问MongoDB 服务
[root@localhost bin]# ./mongod --bind_ip 192.168.1.103
客户端访问时需要明确指定服务端的IP,否则会报错:
[root@localhost bin]# ./mongo 192.168.1.102
MongoDB shell version: 1.8.1
connecting to: 192.168.1.103/test
2 设置监听端口
官方默认的监听端口是27017,为了安全起见,一般都会修改这个监听端口,避免恶意的连
接尝试,具体如下:
将服务端监听端口修改为28018
[root@localhost bin]# ./mongod --bind_ip 192.168.1.103 --port 28018
端户访问时不指定端口,会连接到默认端口27017,对于本例会报错
[root@localhost bin]# ./mongo 192.168.1.102
MongoDB shell version: 1.8.1
connecting to: 192.168.1.102/test
Sun Apr 15 15:55:51 Error: couldn't connect to server 192.168.1.102 shell/mongo.js:81
exception: connect failed
所以当服务端指定了端口后,客户端必须要明确指定端口才可以正常访问
[root@localhost bin]# ./mongo 192.168.1.102:28018
MongoDB shell version: 1.8.1
connecting to: 192.168.1.102:28018/test
3 使用用户名和口令登录
MongoDB 默认的启动是不验证用户名和密码的,启动MongoDB 后,可以直接用MongoDB 连接
北京麒麟网信息科技有限公司 DBA 王文龙 wangwenlong_2009@live.cn
47 / 91
上来,对所有的库具有root 权限。所以启动的时候指定参数,可以阻止客户端的访问和连接。
先启用系统的登录验证模块, 只需在启动时指定 auth 参数即可,如:
[root@localhost bin]# ./mongod --auth
本地客户端连接一下看看效果;
[root@localhost bin]# ./mongo
MongoDB shell version: 1.8.1
connecting to: test
> show collections;
>
很奇怪,为什么我们启用了登录验证模块,但我们登录时没有指定用户,为什么还可以登录
呢?在最初始的时候 MongoDB 都默认有一个 admin 数据库(默认是空的),
而 admin.system.users 中将会保存比在其它数据库中设置的用户权限更大的用户信息。
注意:当 admin.system.users 中没有添加任何用户时,即使 MongoDB 启动时添加了 --auth
参数,如果在除 admin 数据库中添加了用户,此时不进行任何认证依然可以使用任何操作,
直到知道你在 admin.system.users 中添加了一个用户。
1、建立系统root用户
在admin 库中新添一个用户root:
[root@localhost bin]# ./mongo
MongoDB shell version: 1.8.1
connecting to: test
> db.addUser("root","111")
{
"user" : "root",
"readOnly" : false,
"pwd" : "e54950178e2fa777b1d174e9b106b6ab"
}
> db.auth("root","111")
1
>
本地客户端连接,但不指定用户,结果如下:
[root@localhost bin]# ./mongo
MongoDB shell version: 1.8.1
connecting to: test
> show collections;
Sun Apr 15 16:36:52 uncaught exception: error: {
"$err" : "unauthorized db:test lock type:-1 client:127.0.0.1",
"code" : 10057
}
>
连上test 库了,但进一步操作时有异常,看来MongoDB 允许未授权连接,不能进行任何
北京麒麟网信息科技有限公司 DBA 王文龙 wangwenlong_2009@live.cn
48 / 91
本地客户端连接,指定用户,结果如下:
[root@localhost bin]# ./mongo -u root -p
MongoDB shell version: 1.8.1
Enter password:
connecting to: test
> show collections;
system.indexes
system.users
>
看来指定了用户名之后,访问数据库才是正常
2、建立指定权限用户
MongoDB 也支持为某个特定的数据库来设置用户,如我们为test 库设一个只读的用户
user_reader:
[root@localhost bin]# ./mongo -u root -p
MongoDB shell version: 1.8.1
Enter password:
connecting to: test
> show collections;
system.indexes
system.users
> use test
switched to db test
> db.addUser("user_reader", "user_pwd", true)
{
"user" : "user_reader",
"readOnly" : true,
"pwd" : "0809760bb61ee027199e513c5ecdedc6"
}
>
客户端用此用户来访问:
[root@localhost bin]# ./mongo -u user_reader -p
MongoDB shell version: 1.8.1
Enter password:
connecting to: test
> show collections;
system.indexes
system.users

脚本
./mongo test --eval "printjson(db.t1.count())"
MongoDB shell version: 1.8.1
connecting to: test
7
t1_count.js 就是我们要执行的文件,里面的内容如下
[root@localhost bin]# cat t1_count.js
var totalcount = db.t1.count();
printjson('Total count of t1 is : ' + totalcount);
printjson('-----------------------');
下面我们将执行这个文件
[root@localhost bin]# ./mongo t1_count.js
MongoDB shell version: 1.8.1
connecting to: test
"Total count of t1 is : 7"
"-----------------------"

./mongo --quiet t1_count.js
"Total count of t1 is : 7"
"-----------------------"
[root@localhost bin]#
通过指定quiet 参数,即可以将一些登录信息屏蔽掉,这样可以让结果更清晰
查看活动进程,便于了解系统正在做什么,以便做下一步判断
> db.currentOp();
> // 等同于: db.$cmd.sys.inprog.findOne()
{ inprog: [ { "opid" : 18 , "op" : "query" , "ns" : "mydb.votes" ,
"query" : "{ score : 1.0 }" , "inLock" : 1 }
]
}
字段db.killOp(1234/*opid*/)
> // 等同于: db.$cmd.sys.killop.findOne({op:1234})

/Apps/mongo/bin/mongo --port 28011
MongoDB shell version: 1.8.2
connecting to: 127.0.0.1:28011/test
Thu Aug  4 19:20:18 Error: couldn't connect to server 127.0.0.1:28011 shell/mongo.js:81
exception: connect failed


配置replica sets 成功 增加删除节点都灭有问题

但是主节点shutdown 后不知道如何再加入 复制环境中
除非把以前的数据都清理掉 。 或者把现有的复制从节点数据copy过来复制 /Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r4 --fork --port 28014 --dbpath /data/data/r4 --logpath=/data/log/r4.log --logappend --fastsyncr1 --logpath=/data/log/r1.log --logappend

但是这样 他的  rs.status()
{
        "set" : "rs1",
        "date" : ISODate("2011-08-04T10:59:34Z"),
        "myState" : 1,
        "members" : [
                {
                        "_id" : 1,  ---------这个id号会丢失
Bruce_lee 7:24:47 PM
不知道有没有办法让重启后的 节点保持原来的id号


shutdown 之后 启动是正常的  就留下最后一点  
就是某个节点remove 从节点后, 重新加入的时候他的id号会改变 (最好的办法 是   scp -r /data/data/r3 /data/data/r4
/Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r4 --fork --port 28014 --dbpath
/data/data/r4 --logpath=/data/log/r4.log --logappend --fastsync
摸索了好半天 没有英文帮助 只能根据现有的材料想办法  
启动正常 日志有问题
Thu Aug  4 20:01:23 [initandlisten] exception in initAndListen std::exception: old lock file, terminating
Thu Aug  4 20:01:23 dbexit:
Thu Aug  4 20:01:23 [initandlisten] shutdown: going to close listening sockets...

所以把该机器下的 lock文件删除之后重新启动是ok的
有缺点的是 他的 id不是以前的了。 这是算新加入的了。 跟oracle rac不一样 。 rac的节点名不会轻易变

论坛徽章:
0
6 [报告]
发表于 2011-08-04 20:15 |只看该作者
慢查询 跟mysql5.5 一样存放在db 里
profile 的级别可以取0,1,2 三个值,他们表示的意义如下:
 0 – 不开启
 1 – 记录慢命令 (默认为>100ms)
 2 – 记录所有命令
Profile 记录在级别1 时会记录慢命令,那么这个慢的定义是什么?上面我们说到其默认为
100ms,当然有默认就有设置,其设置方法和级别一样有两种,一种是通过添加–slowms 启
动参数配置。第二种是调用db.setProfilingLevel 时加上第二个参数:
db.setProfilingLevel( level , slowms )
db.setProfilingLevel( 1 , 10 );
18.2 查询 Profiling 记录
与MySQL 的慢查询日志不同,MongoDB Profile 记录是直接存在系统db 里的,记录位置
system.profile ,所以,我们只要查询这个Collection 的记录就可以获取到我们的 Profile 记
录了。列出执行时间长于某一限度(5ms)的 Profile 记录:
db.system.profile.find( { millis : { $gt : 5 } } )

查看最新的 Profile 记录:
db.system.profile.find().sort({$natural:-1}).limit(1)
> db.system.profile.find().sort({$natural:-1}).limit(1)
{ "ts" : ISODate("2012-05-20T16:50:36.321Z"), "info" : "query test.system.profile reslen:1219
nscanned:8 \nquery: { query: {}, orderby: { $natural: -1.0 } } nreturned:8 bytes:1203", "millis" :
0 }
>
字段说明:
 ts: 该命令在何时执行
 info: 本命令的详细信息
 reslen: 返回结果集的大小
 nscanned: 本次查询扫描的记录数
 nreturned: 本次查询实际返回的结果集
 millis: 该命令执行耗时,以毫秒记
MongoDB Shell 还提供了一个比较简洁的命令show profile,可列出最近5 条执行时间超过
1ms 的 Profile 记录。
性能优化方法
1 索引 2 限制返回结果数目  3 查询有效字段 4 capped Collections 比普通Collections 的读写效率高
(但是 Capped Collections 可以insert 和update 操作;不能delete 操作。只能用drop()方法
删除整个Collection  这个估计很难被用到) 5 Server Side Code Execution  也就是使用它的存储过程
6 使用hints  或者profile  注意Profiling 功能肯定是会影响效率的,但是不太严重,原因是他使用的是system.profile 来记
录,而system.profile 是一个capped collection 这种collection 在操作上有一些限制和特点,
北京麒麟网信息科技有限公司 DBA 王文龙 wangwenlong_2009@live.cn
58 / 91
但是效率更高

论坛徽章:
0
7 [报告]
发表于 2011-08-04 20:21 |只看该作者
本帖最后由 liyihongcug 于 2011-08-04 20:38 编辑

Sharding分片
这是一种将海量的数据水平扩展的数据库集群系统,数据分表存储在sharding 的各个节点
上,使用者通过简单的配置就可以很方便地构建一个分布式MongoDB 集群。
MongoDB 的数据分块称为 chunk。每个 chunk 都是 Collection 中一段连续的数据记录,通
/Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r0 --fork --port 28010 --dbpath /data/data/r0 --logpath=/data/log/r0.log --logappend  --fastsync
/Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r1 --fork --port 28011 --dbpath /data/data/ata/data/r1 --logpath=/data/log/r1.log --logappend  --fastsync
/Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r3 --fork --port 28013 --dbpath /data/data/r3 --logpath=/data/log/r3.log --logappend
/Apps/mongo/bin/mongod --replSet rs1 --keyFile /data/key/r4 --fork --port 28014 --dbpath /data/data/r4 --logpath=/data/log/r4.log --logappend --fastsyncr1 --logpath=/data/log/r1.log                              --logappend常最大尺寸是 200MB,超出则生成新的数据块。


要构建一个 MongoDB Sharding Cluster,需要三种角色:
 Shard Server
即存储实际数据的分片,每个Shard 可以是一个mongod 实例,也可以是一组mongod 实例
构成的Replica Set。为了实现每个Shard 内部的auto-failover,MongoDB 官方建议每个Shard
为一组Replica Set。
 Config Server
为了将一个特定的collection 存储在多个shard 中,需要为该collection 指定一个shard key,
例如{age: 1} ,shard key 可以决定该条记录属于哪个chunk。Config Servers 就是用来存储:
所有shard 节点的配置信息、每个chunk 的shard key 范围、chunk 在各shard 的分布情况、
该集群中所有DB 和collection 的sharding 配置信息。
 Route Process
这是一个前端路由,客户端由此接入,然后询问Config Servers 需要到哪个Shard 上查询或
保存记录,再连接相应的Shard 进行操作,最后将结果返回给客户端。客户端只需要将原本
发给mongod 的查询或更新请求原封不动地发给Routing Process,而不必关心所操作的记录
存储在哪个Shard 上。
下面我们在同一台物理机器上构建一个简单的 Sharding Cluster:


/Apps/mongo/bin/mongod --shardsvr --port 20000 --dbpath /data/shard/s0 --fork --logpath /data/shard/log/s0.log --directoryperdb
/Apps/mongo/bin/mongod --shardsvr --port 20001 --dbpath /data/shard/s1 --fork --logpath /data/shard/log/s1.log --directoryperdb
/Apps/mongo/bin/mongod --configsvr --port 30000 --dbpath /data/shard/config --fork --logpath /data/shard/log/config.log --directoryperdb
/Apps/mongo/bin/mongos --port 40000 --configdb localhost:30000 --fork --logpath /data/shard/log/route.log --chunkSize 1

/Apps/mongo/bin/mongo admin --port 40000
MongoDB shell version: 1.8.2
connecting to: 127.0.0.1:40000/admin
db.runCommand({ addshard:"localhost:20000" })
{ "shardAdded" : "shard0000", "ok" : 1 }
> db.runCommand({ addshard:"localhost:20001" })
{ "shardAdded" : "shard0001", "ok" : 1 }
> db.runCommand({ enablesharding:"test" })
{ "ok" : 1 }
> db.runCommand({ shardcollection: "test.users", key: { _id:1 }})
{ "collectionsharded" : "test.users", "ok" : 1 }
> use test
switched to db test
> for (var i = 1; i <= 500000; i++) db.users.insert({age:i, name:"wangwenlong", addr:"Beijing",country:"China"})

> > db.users.stats()
{

Replica Sets + Sharding
MongoDB Auto-Sharding 解决了海量存储和动态扩容的问题,但离实际生产环境所需的高可
靠、高可用还有些距离,所以有了” Replica Sets + Sharding”的解决方案:
 Shard:
使用 Replica Sets,确保每个数据节点都具有备份、自动容错转移、自动恢复能力。
 Config:
使用3 个配置服务器,确保元数据完整性
 Route:
使用3 个路由进程,实现负载平衡,提高客户端接入性能

开放的端口如下:
主机 IP 服务及端口
Server A 192.168.3.231 mongod shard1_1:27017
mongod shard2_1:27018
mongod config1:20000
mongs1:30000
Server B 192.168.3.232 mongod shard1_2:27017
mongod shard2_2:27018
mongod config2:20000
mongs2:30000
Server C 192.168.3.233 mongod shard1_3:27017
mongod shard2_3:27018
mongod config3:20000
mongs3:30000

论坛徽章:
0
8 [报告]
发表于 2011-08-23 19:23 |只看该作者
* ome
    * kafka0102的侧面照
http://tech.chinaunix.net/a2011/0714/1218/000001218066.shtml
对mongodb进行java编程

Posted in java, nosql on 七月 3rd, 2010 by kafka0102

本周实验性地使用上mongodb,应用场景很简单,所以现在对mongodb了解也不是很深入。本文主要介绍mongodb的java客户端编程,这方面的内容也很简单,这里只是做个总结。不得不说,像mongodb这种介于kv和sql之间的存储,对很多的互联网应用很合适。mongodb现在的应用案例已经很多,并且社区的活跃度很高(国内也有不少人对其有很深的研究,如果有时间和精力,或许我也会投入一些对mongodb的研究),很值得期待。

言归正传,下面总结下使用Java开发mongodb应用的一些点滴。在Java中和mongodb交互的最直接的选择就是使用MongoDB Java Driver,其下载地址是:http://github.com/mongodb/mongo-java-driver/downloads。总的来说,在Java中操作mongodb的API还是很简洁,下面对其一些常见的使用做些介绍。
1、连接数据库

和mongodb建立连接的示例代码如下:

        Mongo m = new Mongo("localhost",27017);
        DB db = m.getDB("db_test";

尽管这里获得了表示mongodb的db_test数据库连接的对象db,但这时并没有真正和mongodb建立连接,所以即便这时数据库没起来也不会抛出异常,尽管你还是需要catch它的实例化过程。mongodb的java driver对连接做了池化处理,所以应用中只需要实例化一个Mongo对象即可,对它的操作是线程安全的,这对开发使用来说真的是很方便。
2、取得DBCollection

mongodb中的collection在Java中使用DBCollection表示(这是一个抽象类,尽管你不必需要知道),创建DBCollection实例也是一行代码,和创建DB实例一样,这个操作并不涉及真正的和数据库之间的通信。

        DBCollection coll = db.getCollection("collection1";

要获得类似mysql中“show tables”功能,可以使用如下代码:

        Set<String> colls = db.getCollectionNames();
        for (String s : colls) {
            System.out.println(s);
        }

3、插入文档

mongodb存储JSON格式的文档,而在Java中表示这种数据格式的最简便的类就是Map了。MongoDB Java Driver中提供的BasicDBObject就是个Map(它继承自LinkedHashMap并实现DBObject接口),它会将Map中的数据转换成BSON格式传输到mongodb。下面是插入文档的示例:

        DBCollection coll = db.getCollection("collection1";
        BasicDBObject doc = new BasicDBObject();
        doc.put("name", "kafka0102";
        doc.put("age", 2;
        doc.put("time", new Date());
        coll.insert(doc);

mongodb中每个插入的文档会产生个唯一标识_id。当调用coll.insert(doc);时,driver会检查其中是否有_id字段,如果没有则自动生成ObjectId实例来作为_id的值,这个ObjectId由4部分编码而成:当前时间、机器标识、进程号和自增的整数。
insert函数也支持插入文档列表:

insert(List<DBObject> list)

而提交操作也有update( DBObject q , DBObject o )、remove( DBObject o )。
4、查询文档
4.1、findOne

findOne是查询满足条件的第一条记录(不意味着数据库满足条件的只有一条记录),查询条件使用DBObject表示,示例如下:

        DBCollection coll = db.getCollection("collection1";
        BasicDBObject cond = new BasicDBObject();
        cond.put("name", "kafka0102";
        cond.put("age", 2;
        DBObject ret = coll.findOne(cond);
        System.out.println(ret);

返回结果是个DBObject,可以通过get(key)来取值。对于查询条件,可以通过嵌套多层来表示复杂的格式,比如:

        query = new BasicDBObject();
        query.put("i", new BasicDBObject("$gt", 50));  // e.g. find all where i > 50

4.2、find

find函数是查询集合的,它返回的DBCursor是DBObject的迭代器,使用示例如下:

        DBCollection coll = db.getCollection("collection1";
        BasicDBObject cond = new BasicDBObject();
        cond.put("i", new BasicDBObject("$gt", 20).append("$lte", 30));
        DBCursor ret = coll.find(cond);
        while(ret.hasNext()) {
           System.out.println(ret.next());
        }

5、使用索引

创建索引语句如:coll.createIndex(new BasicDBObject(“i”, 1)); ,其中i表示要索引的字段,1表示升序(-1表示降序)。可以看到,DBObject成为java客户端通用的结构表示。查看索引使用 DBCollection.getIndexInfo()函数。
6、MongoDB Java Driver的并发性

前面提到,Java MongoDB Driver使用了连接的池化处理,这个连接池默认是保持10个连接,可以通过Option进行修改,在应用中使用Mongo的一个实例即可。连接池中的每个连接使用DBPort结构表示(而不是DBCollection),并寄存于DBPortPool中,所以对DBCollection的操作并不意味着使用同一个连接。如果在应用的一次请求过程中,需要保证使用同一个连接,可以使用下面的代码片断:

        DB db...;
        db.requestStart();
        //code....
        db.requestDone();

在requestStart和requestDone之间使用的连接就不是来自于DBPortPool,而是当前线程中的ThreadLocal结构变量(MyPort中保持了DBPort成员)。
7、其他选择

尽管Java mongodb driver很不错,但就像很多人不使用JDBC而使用一些ORM框架,mongodb的java客户端也有其他的选择。
1)对POJO和DAO的支持。对于那些热衷ORM的人来说,Morphia(http://code.google.com/p/morphia /wiki/QuickStart)是个不错的选择,它通过在POJO中添加注释来实现映射,并提供对DAO的CRUD操作的支持。
2)对DSL的支持。Sculptor就是这样的东西,使用者编写中立的DSL文件,Sculptor将其翻译成代码。这通常不具有吸引力,除非是多语言的应用,能将DSL翻译成多种编程语言,否则除了增加学习成本,没什么收益。
3)对JDBC的支持。mongo-jdbc是这样的东西,但现在还是实验性质的。它或许是想亲近Java程序员,不过它显然不能完全兼容JDBC,而很多Java程序员对JDBC也并不感冒,所以它不是很值得使用。
8、参考资料

1、http://www.mongodb.org/display/DOCS/Java+Tutorial
2、http://api.mongodb.org/java/2.0/index.html

=============================== 华丽的终止符 ================================

本文作者:kafka0102,转载文章请注明来源,谢谢!!
本文链接:http://www.kafka0102.com/2010/07/209.html

论坛徽章:
0
9 [报告]
发表于 2012-01-27 21:55 |只看该作者
谢谢分享。好资料。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP