mongoDb的写和读

标签: mongodb | 发表时间:2015-05-25 20:49 | 作者:lopez
出处:http://www.iteye.com

1. 首先说一下为什么要用mongodb:

 

   数据结构能体现开发者的程序和构想,所以我们始终在寻找方法,让数据结构更有表达力,从而更好地进行应用的建模。所以回到 MongoDB为何流行的话题上,并不是它的扩展性有多好,而是因为数据结构。

   同其他的NoSQL数据库技术相比,MongoDB的扩展性并不是最出色 的,但是它在数据结构上的创新,能够让我们更加轻松地、更直观地对事物进行建模,这对于应用是最重要的 ,也是MongoDB流行的真正原因。

   像MongoDB这样的数据库,在未来将成为操作型数据存储的主要数据库范式,而关系型数据库将起到专用工具的作用。

  举个例子:

  假如一个旅游产品有多个推荐行程,按照我们惯有的面向对象思想建模,我们会建一张产品表来存储产品信息,再建行程表来存储行程信息,两表通过外键productId(产品id)来关联。当需要查询产品名称和行程名称

  的时候,需要两句sql才能查询出结果。如果在mongodb里面,这样的情况你可以直接把产品名称和行程名称以数组的形式存在产品下面,查询的时候只要查到产品,名称就都知道了,只需要一次查询。

 

2.怎么用:

  2.1 一般先新建一个properties文件,这里是mongo.properties.并在此文件中配置好mongodb的访问ip地址以及端口号(把对数据库,缓存等的访问配置在properties文件中便于统一管理)

#mongotest
#访问ip:端口号
mongodb1=10.10.a.aa:aaaa
mongodb2=10.10.x.xx:XXXX

   2.2 引入mongodb的支持jar包。这里用的是mongo-2.7.3.jar。然后接下来的是在spring文件中配置好访问主机,访问端口(就是加载2.1的properties文件),配置如下:

  

<beans>
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location">
            <value>/WEB-INF/conf/mongo.properties</value>//先加载mongo.properties文件,用了spring的jar包读取
        </property>
    </bean>
    <bean id="server1" class="com.mongodb.ServerAddress">
	  <constructor-arg index="0" value="${mongodb1}" />//读取访问ip+端口号,读取语法${mongodb1}有点像jQuery
    </bean>

     <bean id="server2" class="com.mongodb.ServerAddress">
	 <constructor-arg index="0" value="${mongodb2}" />
     </bean>

     <bean id="mongo" class="com.mongodb.Mongo">//将server1和server2以构造器形式注入进 com.mongodb.Mongo		
               <constructor-arg index="0">
			<list>
 				<ref bean="server1" />
				<ref bean="server2" /> 
			</list>
		</constructor-arg>
	</bean>

	<bean id="mongoTemplate" class="com.mangocity.mongodbhelper.MongoTemplate">//将mango注入进MongoTemplate		
                <property name="mongo" ref="mongo" />
		<property name="databaseName" value="xxx1" />//注意了,这里的databaseName指的是MongoDb里面的数据库名
	</bean>
</beans>

   2.3上面通过${mongodb1}将mongodb1的内容加载进来(10.10.a.aa:aaaa),然后以构造器的形式传进ServerAddress,那么ServerAddress的代码是怎么样的呢?让我们看看:

  

    ServerAddress.java:

 public ServerAddress(String host, int port)//构造器
    throws UnknownHostException
  {
    if (host == null)
      host = defaultHost();
    host = host.trim();
    if (host.length() == 0) {
      host = defaultHost();
    }
    int idx = host.indexOf(":");
    if (idx > 0) {
      if (port != defaultPort())
        throw new IllegalArgumentException("can't specify port in construct and via host");
      port = Integer.parseInt(host.substring(idx + 1));//这里会以:分割得出主机号和端口号
      host = host.substring(0, idx).trim();
    }

    this._host = host;
    this._port = port;
    this._all = _getAddress(this._host);
    this._addr = new InetSocketAddress(this._all[0], this._port);
  }

   2.4 然后将server注入进mango,看看Mongo源码是怎么实现的(Mongo根据注入的server获取Mongo的连接):

  

    Mango.java:

public Mongo(ServerAddress left, ServerAddress right)//构造函数,调用Mongo(ServerAddress left, ServerAddress right, MongoOptions options)
throws MongoException
{
this(left, right, new MongoOptions());
}

@Deprecated
public Mongo(ServerAddress left, ServerAddress right, MongoOptions options) //将两个server(即server1和server2)set给全局变量_addrs
throws MongoException
{
this._addr = null;
this._addrs = Arrays.asList(new ServerAddress[] { left, right });
this._options = options;
_applyMongoOptions();
this._connector = new DBTCPConnector(this, this._addrs); //获取这两台主机的连接,这里就不再深入怎么获取到连接了,有空了再分析
this._connector.start();//连接开始

this._cleaner = new DBCleanerThread();
this._cleaner.start();
}

    2.5上面获取到Mongo的连接,还要把Mongo注入到MongoTemplate(用过Hibernate 的人应该知道,Hibernate也有一个hibernateTemplate,需要注入dataSource和sessionFactory),这里可以看下源代码:

   

   MongoTemplate.java:

public class MongoTemplate
  implements MongoOperations
{  
  public static final String IDENTITY = "_id";
  private Mongo mongo;
  private String databaseName = "test";//前面spring配置文件中的配置名称xxx1
  private boolean slaveOk = false;

  public MongoTemplate()//空构造器
  {
  }
  public MongoTemplate(Mongo mongo, String databaseName) { //构造函数,需要那个MongoDB和数据库名称,这里在前面spring的配置文件中 已经注入进去
    this.mongo = mongo;
    this.databaseName = databaseName;
  }
 public <T> T findAndModify(Query query, Update update, Class<T> entityClass, String collectionName)//查找
  {
    DBCollection col = getDB().getCollection(collectionName);
    DBObject updateObj = update.getUpdateObject();
    for (String key : updateObj.keySet()) {
      updateObj.put(key, DBObjectConverter.toDBObjectTypeConvert(updateObj.get(key)));
    }
    DBObject dBObject = col.findAndModify(query.getQueryObject(), updateObj);
    Object obj = DBObjectConverter.fromDBObject(entityClass, dBObject, true);
    return obj;
  }

  public void insert(Object objectToSave, String collectionName) {//插入,调用插入2的方法
    List list = new ArrayList();
    list.add(objectToSave);
    insert(list, collectionName);
  }
   public void insert(Collection<? extends Object> batchToSave, String collectionName) {//插入2,获取DB连接,然后进行插入,有木有像Hibernate的session的感觉!
    DBCollection col = getDB().getCollection(collectionName);
    List list = new ArrayList();
    for (Iterator localIterator = batchToSave.iterator(); localIterator.hasNext(); ) { Object obj = localIterator.next();
      DBObject dBObject = DBObjectConverter.toDBObject(obj, true);
      list.add(dBObject);
    }
    col.insert(list);
  }

  public void update(Query query, Update update, String collectionName) {//更新,获取DB的连接。这里的collectionName就相当于oracle的表名
    DBCollection col = getDB().getCollection(collectionName);
    DBObject updateObj = update.getUpdateObject();
    for (String key : updateObj.keySet()) {
      updateObj.put(key, DBObjectConverter.toDBObjectTypeConvert(updateObj.get(key)));
    }
    col.update(query.getQueryObject(), updateObj);
  }
}
....

    2.6接下来就是把MongoTemplate注入到Hibernate封装好的对数据库访问的bean中,(这里也可以叫DAO),则该DAO获取到了对MongoDb访问的权限,如:
   
<bean id="productDao" class="*.dao.xxxMongoDaoImpl">
	<property name="mongoTemplate" ref="mongoTemplate" />
</bean>
   
    3.MongoDb读、写实例(可以结合MongoTemplate来看)
    读:
    MongoTemplate读的代码:
  public <T> T findById(Object id, Class<T> entityClass, String collectionName) { //先创建Criteria对象,并往对象填值,然后new一个Query对象,
    Criteria criteria = Criteria.where("_id").is(id);                             //并把criteria对象set进Query对象,再调用find方法进行查询,这里entityClass是javaBean,而collectionName是MongoDb的'表名'
    List list = find(new Query(criteria).limit(1), entityClass, collectionName);
    if (list.size() == 1) {
      return list.get(0);
    }
    return null;
  } 

public <T> List<T> find(Query query, Class<T> entityClass, String collectionName) {
    DBCollection col = getDB().getCollection(collectionName);

    DBCursor cursor = col.find(query.getQueryObject(), query.getFieldsObject());//查询得出cursor(list)
    if (query.getSkip() > 0) {
      cursor.skip(query.getSkip());
    }
    if (query.getLimit() > 0) {
      cursor.limit(query.getLimit());
    }
    if (query.getSortObject() != null) {
      cursor.sort(query.getSortObject());
    }

    List newList = new ArrayList();
    for (DBObject dBObject : cursor) {//遍历转化为对象
      Object obj = DBObjectConverter.fromDBObject(entityClass, dBObject, true);
      newList.add(obj);
    }
    return newList;
  }

   MongoDb读实例:
 
 public List<Product> getProduct(Map params) {
    	Criteria criteria = new Criteria();//创建Criteria 对象
    	criteria.and("type").is(params.get("type"));//往criteria set值
    	criteria.and("departure").is(params.get("departure"));
    	criteria.and("destination").is(params.get("destination"));
    	if(params.containsKey("keys")){
    		criteria.and("key").in((Collection)params.get("keys"));
    	}else{
        	criteria.and("key").is(params.get("key"));
    	}
        Query query = new Query(criteria);
        query.skip(int fromIdx);//从哪里开始
        query.limit(int size);//限制多少条
...
    	return getMongoTemplate().find(query , Product.class, "product");//getMongoTemplate()获取MongoTemplate的实例,即可获取MongoDb 的操作权限,
                                                                         //三个参数分别是query对象,对应的javaBean类以及类所对应的MongoDb 的'表名'
    }
   读操作主要关注两个类:Criteria.java和Query.java,有兴趣的可以看源码加深一下理解,这里就不一一展示了。

   写:

   写的话也大概一样,不过先从oracle数据库读出数据,然后进行转换成与MongoDb字段一一对应的javaBean,然后调用MongoTemplate的保存方法即可!

 

public void saveProduct(Product product) {
    getMongoTemplate().save(product, "product");//两个参数分别是Product.java的引  
                                                //用和MongoDb的'表名'(collection)
  }

   

 

 

 

 



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [mongodb] 推荐:

[mongodb] java操作mongodb

- - 数据库 - ITeye博客
           //实例化Mongo对象,连接27017端口.                               //连接名为yourdb的数据库,假如数据库不存在的话,mongodb会自动建立. //从Mongodb中获得名为yourColleection的数据集合,如果该数据集合不存在,Mongodb会为其新建立.

【MongoDB】MongoDB之优化器Profiler

- - CSDN博客数据库推荐文章
在mysql数据库中,慢查询日志经常作为优化数据库的依据, mongodb中依然有类似的功能. Mongodb自带的profiler,可以方便地记录所有耗时的操作,以便于调优;. 一、开始profiler功能. 开启profier功能有两种:. 第一种就是直接在启动参数里面进行设置,就在茄冬mongodb时候添加-profile=级别.

夜说mongodb

- Lianhui Wang - NoSQLFan
前两天本站刚刚分享了wordnik使用MongoDB经验的文章:《Wordnik 的 MongoDB 使用经历》,今天又看到一位朋友对这方面做的总结,分享在这里,供大家参考. 赋闲以后很长没有更新博客了,说忙完全是借口,多半因为没有兴致所致. 今天凌晨比赛多多,趁着比赛的前奏和间隙,遂浏览些技术文章.

MongoDB与内存

- 高春辉 - 火丁笔记
但凡初次接触MongoDB的人,无不惊讶于它对内存的贪得无厌,至于个中缘由,我先讲讲Linux是如何管理内存的,再说说MongoDB是如何使用内存的,答案自然就清楚了. 据说带着问题学习更有效,那就先看一个MongoDB服务器的top命令结果:. 这台MongoDB服务器有没有性能问题. 先讲讲Linux是如何管理内存的.

白话MongoDB(一)

- Ease - 江边潮未尽,枫红一季秋
按照官方的说法,MongoDB是一种可扩展的高性能的开源的面向文档(document-oriented )的数据库,采用C++开发. 注意mongo不是mango(芒果),这个词是从humongous中截取出来的,其野心不言而明,直指海量数据存储. 和其他很多NoSQL不太一样,MongoDB背后有一个专门的商业公司在提供支持和推广,有点类似MySQL AB的模式.

MongoDB 索引

- - 博客园_首页
索引是用来加快查询的,数据库索引与数据的索引类似,有了索引就不需要翻遍整本书,数据库可以直接在索引中查找,. 使得查询速度很快,在索引中找到条目后,就可以直接跳转到目标文档的位置.. 要掌握如何为查询配置最佳索引会有些难度.. MongoDB索引几乎和关系型数据库的索引一样.绝大数优化关系型数据库索引的技巧同样适用于MongoDB..

MongoDB sql操作

- - 数据库 - ITeye博客
1.  基本查询:. 下面的示例等同于SQL语句的where name = "stephen" and age = 35.      --返回指定的文档键值对. 下面的示例将只是返回name和age键值对.      --指定不返回的文档键值对. 下面的示例将返回除name之外的所有键值对.

MongoDB Shareding部署

- - 开源小站
几年前写过 MongoDB的Sharding和replication. 其实现在看起来Replication还是可以,Sharding的部分有点过于简单了. 于是现在重新补充一下,至少也更新下,毕竟现在的MongoDB已经到了2.6,于当时的2.2还是有所差异的. 正常的情况下,应该是有6台主机实现一个比较像样的MongoDB Sharding集群,它们分别是mongos /router1台,config 3台,shard 2台.

MongoDB REST Api介绍

- peigen - NoSQLFan
MongoDB默认会开启一个HTTP协议的端口提供REST的服务,这个端口是你Server端口加上1000,比如你的Server端口为27017,那么这个HTTP端口就是28017,默认的HTTP端口功能是有限的,你可以通过添加–rest参数启动更多功能. 下面是在这个端口通过其RESTFul 的API操作MongoDB数据的几个例子,来源是MongoDB官方文档.