內存測試數據庫

原文:InMemoryTestDatabase        設計    2005年11月22日

更新見文末。

運行時完全在內存裏無需訪問硬盤的數據庫叫做“內存數據庫”。內存數據庫常作爲嵌入式數據庫:當一個進程啓動時被創建,嵌入到這個進程中運行,當進程終止時被銷燬。

儘管大家一般都認爲數據庫應該是個以硬盤爲中心的龐大部件,實際上還存在一個狹小而熱鬧的內存數據庫世界。有些應用系統要求數據訪問速度要快,這些數據被管理但無需被持久化,因爲它們不會改變,或者因爲這些數據可被重新生成(聯想一下路由器的路由表,還有事件張貼板)。

即便開發傳統的數據庫應用系統,你也會發現內存數據庫的妙用,尤其是在做測試的時候。開發一個企業應用系統時,測試套件(test suites)每跑一遍,需要訪問數據庫的那些測試都會花費大量的時間。把這些測試切換到內存數據庫,效果就大不一樣了,運行耗時將大大縮短。要是最近一會沒看見那個綠色進度條,幾乎ThoughtWorks公司的任何一位員工都會心神不寧,所以內存數據庫與我們真是休慼相關。

人們用內存數據庫做測試有兩種方式,一種是把它用作一個支持SQL的內存數據庫程序包,在Java世界裏最流行的要數HSQLDB了,其他領域則有 SQLiteFirebird。這類工具最誘人的一點是允許你用常規的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員工在我們內部郵件列表上發了有幫助的評論。)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章