内存测试数据库

来源:互联网 发布:ipad上淘宝无卖家中心 编辑:程序博客网 时间:2024/05/21 05:58
原文:InMemoryTestDatabase        设计    2005年11月22日

更新见文末。

运行时完全在内存里无需访问硬盘的数据库叫做“内存数据库”。内存数据库常作为嵌入式数据库:当一个进程启动时被创建,嵌入到这个进程中运行,当进程终止时被销毁。

尽管大家一般都认为数据库应该是个以硬盘为中心的庞大部件,实际上还存在一个狭小而热闹的内存数据库世界。有些应用系统要求数据访问速度要快,这些数据被管理但无需被持久化,因为它们不会改变,或者因为这些数据可被重新生成(联想一下路由器的路由表,还有事件张贴板)。

即便开发传统的数据库应用系统,你也会发现内存数据库的妙用,尤其是在做测试的时候。开发一个企业应用系统时,测试套件(test suites)每跑一遍,需要访问数据库的那些测试都会花费大量的时间。把这些测试切换到内存数据库,效果就大不一样了,运行耗时将大大缩短。要是最近一会没看见那个绿色进度条,几乎ThoughtWorks公司的任何一位员工都会心神不宁,所以内存数据库与我们真是休戚相关。

人们用内存数据库做测试有两种方式,一种是把它用作一个支持SQL的内存数据库程序包,在Java世界里最流行的要数HSQLDB了,其他领域则有 SQLite和Firebird。这类工具最诱人的一点是允许你用常规的SQL做查询,但有一点需注意:它们支持的SQL方言可能与目标数据库并不完全相同,也可能不提供目标数据库的全部特性。你也可以在ram磁盘上跑一个基于文件的数据库达到类似的效果,可以让测试与实际产品部署环境之间尽可能接近。

另外一种方式是把所有数据库访问操作都抽取出来放到一个Repository的 后边,这样就能以常规的驻于内存的数据结构替换掉数据库了,要保存一个对象关联图的节点通常用几个哈希表就够了。采用Repository模式有一个好 处,就是无论是不是SQL数据源,其访问方式是统一的,可以拿非SQL数据源作为测试桩把数据库替换掉。这意味着我们用的O-R映射工具也隐藏于Repository的后面。

然而,有少数一些人对内存数据库这种东西着实反感,因为他们认为内存数据库诱使人们把SQL或O-R映射代码在领域模型(domain model)中散得到处都是。虽然在内存里运行SQL可以免除访问耗时之苦,但它却扮演了文过饰非的“除臭剂”角色,让缺失Repository层的臭味不那么明显了。

到目前为止,尽管测试是采用内存数据库的主要动机,但我觉得它还能带来其他好处。今天内存大小对于很多应用都不再是个限制因素了,可以把全部数据装 到内存中运行。例如,一个系统的状态变化记录在一个事件日志里,你在想着用什么办法来监控这份日志,这时内存数据库可被用作日志信息的一个缓存,就能随需 重新载入日志或给某状态“拍个快照”。这种方式能使数据读取很多但写入很少的系统获得很高的可伸缩性以及性能上的提升。我见到过好几个系统,用内存数据库 获得了非常高的性能。与用于测试不同的是,在这些场合,人们更愿意选用合适的商业数据库,而做测试时人们更青睐开源系统。

Prevayler对采用这种方法非常关注。我还了解到,有人尝试后发现它与内存中的objects紧密耦合在一起,另外,迁移工具的缺乏也导致很严重的问题。但我认为这种系统变化日志的持久化方式今后会是个成果丰硕的探索领域。

后续讨论

写完上边的文字后我收到了几封有意思的邮件,我想我应该拿出来与大家分享这些观点。

有人回信说,他喜欢把内存数据库用在那些用SQL胜任有余但用object却蹩手蹩脚的任务上。确实存在一些情况,用SQL比用object或过程化代码更能漂亮地解决问题,尽管我通常认为喜欢以SQL方式思考问题的开发人员只占少数。

我的同事Steve Sparks告诉我,一个近期项目的测试中,他们在系统启动时把数据从在线数据库中取出来,再把它们保存到一个文件里来初始化一个内存里的 Repository,之后的查询就不需要再碰数据库了。我第一次见到这种做法是在C3项目中,它把数据保存在一个哈希表中,而把SQL查询字符串用作哈 希表的键,如果某键没有对应的值,再转向DB2查询,同时把结果保存在哈希表中。

Steven Graves指出我原来写的那篇“内存数据库”没能真正把内存数据库的主要用途讲透,因此,我重写了一下,并把标题改名为“内存测试数据库”。

(感谢Peter Becker、Zane Rockenbaugh还有Steve Sparks给我的评论,还要感谢好多位没给出姓名的ThoughtWorks员工在我们内部邮件列表上发了有帮助的评论。)