mongoDb的写和读
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:
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访问的权限,如: