<img src="@ViewData["html"]" />
作为测试代码,我就在界面上面写了液散一个image框,用来显示从MongoDB数据库中读取出来的图片。
HomeController代码
public ActionResult Index(){ViewData["html"蠢链] = "/MongodbHelp/ProcessRequest?actions=DOWNLOAD&value=lf.png" return View() }
后面的代码组成相信凡是接触过MVC的读者都能看懂这个东西,后面我就直接写死了一个图片的名称。
MongodbHelpController
连接数据库的方法
private static MongoDatabase DB public static string fileTable = "fs"//数据库中的表名称//Sets up the environment.public void Init(){
//我们可以在配置文件中读取string ConnectionString = "127.0.0.1" //ConfigurationManager.AppSettings["mondoDbConnection"] if (String.IsNullOrEmpty(ConnectionString)){throw new ArgumentNullException("Connection string not found.") }MongoServerSettings mongoSetting = new MongoServerSettings() mongoSetting.MaxConnectionPoolSize = 15000//设定最大连接池mongoSetting.WaitQueueSize = 500//设定等待队列数mongoSetting.Server = new MongoServerAddress(ConnectionString, 27017) int count = MongoServer.MaxServerCount MongoServer server = MongoServer.Create(mongoSetting)//创建连接数据文件DB = server.GetDatabase("local")//创建数据库连接}
用来判断我们进行的方法是哪一个,上传文件还是下载文件,在这只给大家介绍下载的方法;
闹档氏
public void ProcessRequest(){Init()//initialize the mongostring action = Request.QueryString["actions"] switch (action){case "LIST": GetFileList()break//获取文件列表case "UPLOAD": Upload()break//上传文件case "DELETE": Delete()break//删除文件case "DOWNLOAD": DownFile()break//下载文件}}
下载文件的类
//下载文件public void DownFile(){string filename = Request.QueryString["value"] Response.ContentType = "application/octet-stream" //context.Response.ContentType = "audio/mpeg" Response.AddHeader("Content-Disposition", "attachmentfilename=" + filename) MongoGridFSSettings fsSetting = new MongoGridFSSettings() { Root = fileTable } MongoGridFS fs = new MongoGridFS(DB, fsSetting) MongoGridFSFileInfo gfInfo = new MongoGridFSFileInfo(fs, filename) //方法一,很简洁fs.Download(Response.OutputStream, filename) Response.End() }
通过这几段代码,我们就轻松的完成MongoDB数据的文件读取 *** 作。
这种用法对于以下应用场合来讲,超实用:
置于慢速RDBMS系统之前的写 *** 作密集型高速缓存
嵌入式系统
无需持久化数据的PCI兼容系统
需要轻量级数据库而且库中数据可以很容易清除掉的单元测试(unit testing)
如果这一切可以实现就真是太优雅了:我们就能够巧妙地在不涉及磁盘 *** 作的情况下利用MongoDB的查询/检索功能。可能你也知道,在99%的情况下,磁盘IO(特别掘咐是随机IO)是系统的瓶颈,而且,如果你要写入数据的话,磁盘 *** 作是无法避免的。
MongoDB有一个非常酷的设计决策,就是她可以使用内存影射文件(memory-mapped file)来处理对磁盘文件中数据的读写请求。这也就是说,MongoDB并不对RAM和磁盘这两者进行区别对待,只是将文件看作一个巨大的数组,然后按照判橘纯字节为单位访问其中的数据,剩下的都交由 *** 作系统(OS)去处理!就是这个设计决策,才使得MongoDB可以无需任何修改就能够运行于RAM之中。
实现方法
这一切都是通过使用一种叫做tmpfs的特殊类型文件系统实现的。在Linux中它看上去同常规的文件系统(FS)一样,只是它完全位于RAM中(除非其大小超过了RAM的大小,此时它还可以进行swap,这个非常有用!)。我的服务器中有32GB的RAM,下面让我们创建一个16GB的 tmpfs:
# mkdir /ramdata # mount -t tmpfs -o size=16000M tmpfs /ramdata/ # df Filesystem 1K-blocks Used Available Use% Mounted on /dev/xvde1 5905712 4973924 871792 86% / none 15344936 0 15344936 0% /dev/shm tmpfs 16384000 0 16384000 0% /ramdata
接下来要用适当的设置启动MongoDB。为了减小浪费的RAM数量,应该把smallfiles和noprealloc设置为true。既然现在是基于RAM的,这么做完全不会降低性能。此时再使用journal就毫无意义了,所以应该把nojournal设置为true。
dbpath=/ramdata nojournal = true smallFiles = true noprealloc = true
MongoDB启动之后,你会发现她运行得非常好,文件系统中的文件也正如期待的那样出现了:
# mongo MongoDB shell version: 2.3.2 connecting to: test > db.test.insert({a:1}) > db.test.find() { "_id" : ObjectId("51802115eafa5d80b5d2c145"), "a" : 1 } # ls -l /ramdata/ total 65684 -rw-------. 1 root root 16777216 Apr 30 15:52 local.0 -rw-------. 1 伍尘root root 16777216 Apr 30 15:52 local.ns -rwxr-xr-x. 1 root root 5 Apr 30 15:52 mongod.lock -rw-------. 1 root root 16777216 Apr 30 15:52 test.0 -rw-------. 1 root root 16777216 Apr 30 15:52 test.ns drwxr-xr-x. 2 root root 40 Apr 30 15:52 _tmp
现在让我们添加一些数据,证实一下其运行完全正常。我们先创建一个1KB的document,然后将它添加到MongoDB中4百万次:
> str = "" > aaa = "aaaaaaaaaa" aaaaaaaaaa > for (var i = 0 i < 100 ++i) { str += aaa } > for (var i = 0 i < 4000000 ++i) { db.foo.insert({a: Math.random(), s: str})} > db.foo.stats() { "ns" : "test.foo", "count" : 4000000, "size" : 4544000160, "avgObjSize" : 1136.00004, "storageSize" : 5030768544, "numExtents" : 26, "nindexes" : 1, "lastExtentSize" : 536600560, "paddingFactor" : 1, "systemFlags" : 1, "userFlags" : 0, "totalIndexSize" : 129794000, "indexSizes" : { "_id_" : 129794000 }, "ok" : 1 }
可以看出,其中的document平均大小为1136字节,数据总共占用了5GB的空间。_id之上的索引大小为130MB。现在我们需要验证一件 非常重要的事情:RAM中的数据有没有重复,是不是在MongoDB和文件系统中各保存了一份?还记得MongoDB并不会在她自己的进程内缓存任何数据,她的数据只会缓存到文件系统的缓存之中。那我们来清除一下文件系统的缓存,然后看看RAM中还有有什么数据:
# echo 3 > /proc/sys/vm/drop_caches # free total used free shared buffers cached Mem: 30689876 6292780 24397096 0 1044 5817368 -/+ buffers/cache: 474368 30215508 Swap: 0 0 0
可以看到,在已使用的6.3GB的RAM中,有5.8GB用于了文件系统的缓存(缓冲区,buffer)。为什么即使在清除所有缓存之后,系统中仍然还有5.8GB的文件系统缓存??其原因是,Linux非常聪明,她不会在tmpfs和缓存中保存重复的数据。太棒了!这就意味着,你在RAM只有一份数据。下面我们访问一下所有的document,并验证一下,RAM的使用情况不会发生变化:
果不其然! :)
复制(replication)呢?
既然服务器在重启时RAM中的数据都会丢失,所以你可能会想使用复制。采用标准的副本集(replica set)就能够获得自动故障转移(failover),还能够提高数据读取能力(read capacity)。如果有服务器重启了,它就可以从同一个副本集中另外一个服务器中读取数据从而重建自己的数据(重新同步,resync)。即使在大量数据和索引的情况下,这个过程也会足够快,因为索引 *** 作都是在RAM中进行的 :)
有一点很重要,就是写 *** 作会写入一个特殊的叫做oplog的collection,它位于local数据库之中。缺省情况下,它的大小是总数据量的5%。在我这种情况下,oplog会占有16GB的5%,也就是800MB的空间。在拿不准的情况下,比较安全的做法是,可以使用oplogSize这个选项为oplog选择一个固定的大小。如果备选服务器宕机时间超过了oplog的容量,它就必须要进行重新同步了。要把它的大小设置为1GB,可以这样:
oplogSize = 1000
分片(sharding)呢?
既然拥有了MongoDB所有的查询功能,那么用它来实现一个大型的服务要怎么弄?你可以随心所欲地使用分片来实现一个大型可扩展的内存数据库。配置服务器(保存着数据块分配情况)还还是用过采用基于磁盘的方案,因为这些服务器的活动数量不大,老从头重建集群可不好玩。
注意事项
RAM属稀缺资源,而且在这种情况下你一定想让整个数据集都能放到RAM中。尽管tmpfs具有借助于磁盘交换(swapping)的能力,但其性能下降将非常显著。为了充分利用RAM,你应该考虑:
使用usePowerOf2Sizes选项对存储bucket进行规范化
定期运行compact命令或者对节点进行重新同步(resync)
schema的设计要相当规范化(以避免出现大量比较大的document)
1:Jsp页面:
[html] view plain copy
<td><img src="${ctx}/mongoImg/show"></td>
2:xml配置:
[html] view plain copy
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mongo="巧埋轿http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<mongo:mongo host="${resource.db.host}" port="${resource.db.port}" />
<mongo:db-factory id="液和mongoDbFactory" dbname="gate" mongo-ref="mongo" />
<bean class="org.springframework.data.mongodb.gridfs.GridFsTemplate">
<constructor-arg ref="mongoDbFactory" />
<constructor-arg ref="converter" />
</bean>
<mongo:mapping-converter id="converter"/>
</beans>
3:java后台代码
[java] view plain copy
package com.crscic.igms.manager.web
import java.io.OutputStream
import java.util.List
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.mongodb.gridfs.GridFsTemplate
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.RequestMapping
import com.mongodb.gridfs.GridFSDBFile
@Controller
@RequestMapping(value = "/mongoImg")
public class MongoImgController {
@Autowired
GridFsTemplate gridFsTemplate
@RequestMapping(value = "/show")
public 孝肆void show(HttpServletRequest req, HttpServletResponse resp){
try {
OutputStream out = resp.getOutputStream()
resp.setContentType("image/png")
List<GridFSDBFile> find = gridFsTemplate.find(null)
GridFSDBFile gridFSDBFile = find.get(0)
gridFSDBFile.writeTo(out)
out.flush()
out.close()
} catch (Exception e) {
e.printStackTrace()
}
}
}
在JAVA代码中,因为只是个例子而已,所以我使用的是gridFsTemplate.find(null)查询的全部图片,而且数据库中只有2条数据,我这里就把第一条数据查出来作为例子了。各位可以根据自己的业务需要,在页面传递参数进来,并且查询特定的数据。欢迎分享,转载请注明来源:内存溢出
评论列表(0条)