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文件),配置如下:
/WEB-INF/conf/mongo.properties //先加载mongo.properties文件,用了spring的jar包读取//读取访问ip+端口号,读取语法${mongodb1}有点像jQuery //将server1和server2以构造器形式注入进 com.mongodb.Mongo //将mango注入进MongoTemplate //注意了,这里的databaseName指的是MongoDb里面的数据库名
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:
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; } public2.6接下来就是把MongoTemplate注入到Hibernate封装好的对数据库访问的bean中,(这里也可以叫DAO),则该DAO获取到了对MongoDb访问的权限,如:T findAndModify(Query query, Update update, Class 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); } } ....
publicMongoDb读实例:T findById(Object id, Class 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 List find(Query query, Class 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; }
public List读操作主要关注两个类:Criteria.java和Query.java,有兴趣的可以看源码加深一下理解,这里就不一一展示了。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 的'表名' }
写:
写的话也大概一样,不过先从oracle数据库读出数据,然后进行转换成与MongoDb字段一一对应的javaBean,然后调用MongoTemplate的保存方法即可!
public void saveProduct(Product product) { getMongoTemplate().save(product, "product");//两个参数分别是Product.java的引 //用和MongoDb的'表名'(collection) }