用于 JavaScript 應用程序的五大嵌入式數據庫
我們習慣于將數據庫視為巨大的存儲平臺,我們可以在其中存儲我們需要的所有數據,然后通過某種形式的查詢語言檢索它。擴展這些數據庫,保持信息的一致性和容錯性本身就是一個挑戰。但是,當我們的數據需求非常小時會發生什么?
當RedShift、BigQuery、甚至MySQL對我們微小的數據需求來說是一個太大的解決方案時,會發生什么?好吧,事實證明,有一個應用程序可以解決這個問題。事實上,有很多選擇,所以在這里,我將介紹5大嵌入式數據庫,以滿足你的微小數據需求。
什么是嵌入式數據庫?
當我們讀到“嵌入式”這個詞時,90% 的人會得出結論,我說的是物聯網或移動設備。但這種情況并非如此。
反正不是唯一的情況。誠然,這些系統的資源非常有限,這使得大多數傳統的數據庫系統很難配置和安裝在那里。
但是對于小型數據庫還有其他的用例,也就是將它們嵌入到軟件產品中。例如,想象一下通過您的IDE在一個大型代碼存儲庫上進行搜索。IDE可以嵌入一個反向索引數據庫,允許您搜索關鍵字并快速獲取相關文件的參考。或者在您最喜歡的電子郵件桌面客戶端上執行搜索時,該客戶端很可能也有一個嵌入式數據庫。所有的電子郵件都存儲在那里并被編入索引,所以你可以快速輕松地訪問這些信息。
到目前為止,您可能已經了解了嵌入式數據庫的另一個巨大好處,即它們不需要與網絡調用進行交互。與標準數據庫相比,這是一個巨大的性能提升。從本質上講,在正常的開發中,你希望把數據庫放在自己的服務器(或服務器集群)上,這樣它的資源消耗就不會影響到你架構中的其他組件,而對于嵌入式數據庫,你希望它們盡可能地靠近客戶端代碼。這就減少了它們之間的延遲,避免了對通信渠道(即網絡)的依賴。
現在,這個想法可以有多種形式,從使用 JSON 文件作為主存儲的快速內存數據庫,到可以使用類似 SQL 的語言進行查詢的高效微型關系數據庫。
讓我們來看看5種選擇。
LowDB
讓我們從簡單的開始,LowDB 是一個小型的內存數據庫。這是一個非常基本的解決方案,但它解決了一個非常簡單的用例:需要從基于 JavaScript 的項目中存儲和訪問類似 JSON 的結構(即文檔)。
LowDB的一個主要好處是它可以從JavaScript中使用,也就是說:它可以用于后端、桌面和瀏覽器代碼。
在后端,你可以將它與 Node.js 一起使用,對于桌面開發,它可以集成到一個 Electron 項目中,最后,它也可以通過其集成的 JS 運行時直接在瀏覽器上運行。
這個數據庫提供的API也相當簡單和簡約,它不提供任何開箱即用的搜索功能。它只限于將一個JSON文件的數據加載到一個數組變量中,讓你(用戶)以你認為合適的方式找到你要找的東西。
例如,看看下面的代碼:
- import { LowSync, JSONFileSync } from 'lowdb'
- const title = "This is a test"
- const adapter = new JSONFileSync('file.json')
- const db = new LowSync(adapter)
- db.read() //將文件內容加載到內存中
- db.data ||= { posts: [] } //默認值
- db.data.posts.push({ title }) //將數據添加到“集合”中
- db.write() //通過將數據保存到JSON文件來持久化數據
- //任何類似于查找的操作都由用戶自己來完成
- let record = db.data.posts.find( p => p.title == "Hello world")
- if(!record) {
- console.log("No data found!")
- } else {
- console.log("== Record found ==")
- console.log(record)
- }
正如你所看到的,這里有趣的部分不是默認的行為,而是我正在使用一個叫做 JSONFileSync 的適配器。我可以很容易地使用一個由我創建的自定義的適配器,這才是這個數據庫的真正強項。
它具有高度的可擴展性并與 TypeScript 兼容,后者為數據存儲提供了類似于模式的行為(即不允許添加不遵循預設模式的數據)。
如果混合使用這兩種選項,那么LowDB將成為處理本地類似json的數據的有趣選項。
LevelDB
LevelDB 是由 Google 構建的開源鍵值數據庫。它是一種超快但非常有限的鍵值存儲,其中數據按開箱即用的鍵排序存儲。
它只有三個基本操作:Put、Get 和 Delete,沒有別的——如果你仔細想想,有點像 LowDB。
和LowDB一樣,它沒有一個客戶端-服務器封裝器,這意味著沒有辦法從任何語言與它通信,如果你想使用它,你必須使用C/C++庫,如果你想要一個類似服務器的行為,你必須自己封裝它。
就像我們在這里要介紹的大多數案例一樣,功能非常基本,因為它們涵蓋了一個非常簡單但需要的用例:在靠近代碼的地方存儲數據并快速訪問。
該數據庫的存儲架構是圍繞著日志結構的合并樹(LSM),這意味著它被優化為大型的連續寫操作,而不是小型的隨機操作。
LevelDB 的一個主要限制是,一旦打開,它就會在存儲上獲得系統級鎖,這意味著當時只有一個進程可以與數據庫交互。當然,您可以使用多個線程來并行化該進程中的某些操作。但這就是它的范圍。
有趣的是,這個數據庫被用作Chrome的IndexedDB的后臺數據庫,顯然Minecraft Bedrock版也使用它來存儲一些分塊和實體數據(盡管從外觀上看,他們使用的是谷歌實現的略微修改的版本)。
Raima 數據庫管理器
我之前提到過物聯網不是嗎? Raima 是速度最快的數據庫管理器之一,專門針對在資源受限的物聯網設備中運行進行了優化。
資源受限的環境是什么意思? Raima 只需要 350kb 的 RAM 即可運行。這就是我可以極簡的資源利用。
該解決方案的主要特點之一是它完全支持 SQL,這一點在之前的任何解決方案中都沒有出現。它提供了一個關系數據模型,并允許您使用 SQL 語言進行查詢。
與 LevelDB 不同的是,它還允許通過客戶端-服務器架構對數據庫進行多進程訪問(即這種架構允許您比其他架構更遠離源代碼)。如果您決定采用接近源代碼的嵌入式應用程序,您還可以使用多線程來支持對多個數據庫的并發訪問。
Raima的靈活性允許你從傳統的客戶-服務器方法到最有效的(當然也是有限的)使用案例,即由單個客戶消費的單一內存數據庫。但是,嘿,這是一個非常有效的嵌入式數據庫的使用案例。
這種靈活性使它成為一種非常通用的解決方案。當然,每種部署模式都有自己的優點和限制,但是也會針對特定的用例進行優化。因此,請確保您選擇了正確的一個,并從這個數據庫中獲得最大的好處。
Apache Derby
如果你正在尋找另一個非常小的、類似SQL的數據庫,Apache Derby很可能是你正在尋找的東西。
Derby完全是用JAVA編寫的,當它聲稱只有3.5Mb的內存占用時,也損失了一點信譽。畢竟,如果沒有在主機系統上安裝JVM,您就不能運行或使用它。
也就是說,如果您的用例允許使用JVM,那么很好,您可以繼續考慮Derby,否則您可能希望使用更本地的解決方案,如LevelDb或Raima。
但正如我所說,如果您已經在從事 JAVA 項目并且需要集成一個小型、可靠、基于 SQL 的數據庫,那么 Derby 絕對是一個潛在的候選者。
它帶有一個集成的 JDBC 驅動程序,因此不需要額外的依賴項。它既可以在 JAVA 應用程序內的嵌入式模式下工作,也可以作為獨立服務器運行,允許多個應用程序同時與其交互(類似于 Raima 的工作方式,但沒有許多變體)。
說實話,這個項目最大的缺點是它的文檔。它可能是JAVA社區的一個標準,但它對用戶并不友好,大部分的官方鏈接都把讀者送到一個私人的匯合頁面。這里的許多其他解決方案在涉及到文檔時提供了更順暢的體驗,這也有助于他們產品的采用。
solidDB
最后,solidDB提供了一個非常有趣的內存關系數據庫,它同時還可以增強一個持久性模型。聲稱它可以保持兩個數據存儲選項實時同步。這可不是個小要求。
本質上就像這里列出的其他解決方案一樣,solidDB 可以通過 ODBC 或 JDBC 訪問,這允許 JAVA 和 C 應用程序通過 SQL 與其交互。
也像這里列出的一些解決方案一樣,它可以以多種模式部署:
- 高可用性模式。這涉及具有重復數據的多個服務器。當然,這種模式在我們考慮的用例中并不多。
- 共享內存訪問。這個方案非常有趣,因為它不僅將數據保存在內存中(就像已經列出的其他解決方案一樣),而且還允許多個應用程序訪問該內存(因此有共享內存部分)。當然,對共享內存的直接訪問需要由同一節點內的應用程序完成,但是,它還允許基于 JDBC/ODBC 從外部節點訪問相同的數據。將共享內存轉變為具有外部訪問權限的內存數據庫。
由于訪問數據的速度快如閃電,思科、阿爾卡特、諾基亞和西門子等多家知名企業聲稱將使用該數據庫進行關鍵任務操作。
鑒于其所有的部署模式、廣泛的文檔和高需求的客戶名單,我可以看到這是這個名單上最可靠、最穩定、最快速的嵌入式數據庫之一。
嵌入式數據庫是為了處理一個非常具體的用例,或者通過提供快速可靠的數據存儲和最小的延遲,或者通過允許快速安全地訪問數據。這里列出的解決方案通過不同的手段實現這些目標,這取決于你和你的特定環境,以決定哪一個是適合你的。