Mongodb使用json格式存储数据,不像关系型数据库用记录来表示,它是一种nosql数据库。数据存储用key:value形式存储,这样表示好处就是简单。

在项目中,有一个用户的实体User,他有很多朋友,当然他的朋友也在数据库里,为了建立关系,如果在关系数据库中我们会建立一个关系表UserFriend来表示这2个关系,这样表示的优点是结构清晰,缺点也显而易见,必须多执行一次查询才能获得好友id列表。。。而且要想更新好友关系那就更复杂了点,需要批量删除修改。。。

在mongodb里,就可以直接把好友id以数组形式加到用户信息的一个字段里了,这样在获取用户信息时,好友信息就直接获取,大大减少了查询请求,更新时也可以直接设值。这也就是为什么在互联网应用中倾向于使用nosql而不是关系型数据库的原因!简单、高效!

java的语法似乎不怎么喜欢json格式,通常定义一个对象,用setter和getter来操作数据,比较繁琐,却也不得已而为之!(相对来说,python等脚本语言用json很酷,可以直接用a["key"]来获取和设置字段值)。可惜这个项目已经用java来做了,用python估计不太可能了。

mongodb提供的java driver里,存取数据用DBObject,它使用类似map操作方法,把字段和值一个个put进去,读取的话可以用get方法,当时第一次接触,我就想到了用反射(reflect)来操作,获取pojo的每个字段值然后put到DBObject里,于是就写了个互相转化的方法,后来在项目中也就是这样使用了,可我写的这个方法只能处理简单类,字段只能为Integer,Long,String这集中类型,不支持数组和map。。做了一段时间,才发现我在用nosql
数据库实现关系数据库,因为我确实用了一个usrfriend集合来存储用户好友关系。。。

最近才若有所思的发现,我不该这么做,好友id列表应该直接放到用户信息里的。

在mongodb官网发现有很多第三方工具,其中有个morphia的项目,打开首页(http://code.google.com/p/morphia/),一目了然的看到了如何定义实体以及存储和查找,用了下比我这个方便多了,于是毫不犹豫的开始重构代码。。。

下面介绍下如何使用morphia

1.下载最新版本的morphia-xxx.jar 并且加入的 path里。

2.在pojo类用注解@Entity定义一个实体,用@Embedded定义一个潜入类。


3.可以直接存储数组,和map。非常方便的可以嵌套很多信息。原先要建关系表的,可以统统取消了。只用一个

查询就可以把所有信息返回了,在高并发时非常实用。

4.morphia提供了一个dao可以拓展或者实例化使用,我没有拓展,因为用了spring,有依赖注入关系,而拓展这

个DAO需要Datastore,在构造函数里无法给它。只有在注入完毕后我才可以给它。于是只有这样了

public void afterPropertiesSet() throws Exception {
		this.ds = morphia.getDataStore() ;
		dao = new DAO<T, String>(clazz, this.ds); 
	}



5.编写好一些常用接口:



/**
	 * 增加
	 */
	public void add(T t){
		dao.save(t);
	}
	/**
	 * 创建一个查询
	 */
	protected Query<T> createQuery(){
		return dao.createQuery();
	}
	/**
	 * 根据_id查询
	 */
	protected Query<T> createIdQuery(Object _id){
		return dao.createQuery().field("_id").equal(_id);
	}
	/**
	 * 查找一个实体
	 */
	protected T findOne(Query<T> q){
		return dao.findOne(q);
	}

	/**
	 * 根据_id查找
	 */
	public T findById(ObjectId _id){
		return dao.findOne("_id", _id);
	}
	/**
	 * 可查找多个实体
	 */
	protected QueryResults<T> find(Query<T> q){
		return dao.find(q);
	}
	/**
	 * 返回全部实体
	 */
	public List<T> getAll(){
		return this.find(this.createQuery()).asList();
	}
	/**
	 * 分页查找
	 */
	protected QueryResults<T> find(Query<T> q, Page page){
		if(page != null){
			q.limit(page.getPageSize()).offset((page.getPageIndex() - 1) * 

page.getPageSize());
			page.setTotalCount((int) q.countAll());
		}
		return dao.find(q);
	}
	/**
	 * 删除实体
	 */
	protected void delete(T t){
		dao.delete(t);
	} 
	/**
	 * 根据查询删除
	 */
	protected void delete(Query<T> q){
		dao.deleteByQuery(q);
	}

	/**
	 * 根据_id删除
	 */
	public void delById(ObjectId id){
		Query<T> q = this.createIdQuery(id);				
		dao.deleteByQuery(q); 
	}
	/**
	 * 更新
	 */
	protected void update(Query<T> q,  UpdateOperations<T> ops){
		dao.update(q, ops);	
	}
	/**
	 * 已知_id进行添加就是更新覆盖
	 */
	public void update(T t){
		dao.save(t);
	}
	/**
	 * 创建一个更新操作
	 */
	protected UpdateOperations<T> createUpdateOperations(){
		return dao.createUpdateOperations();
	}





这样,在具体使用时,直接定义一个User类,它里面的字段可以使用很多其他类,也可以使用数组,然后直接



save,而query时也会一起带出来,很方便,也可以大大较少数据库请求操作。