Node.js使用數據庫LevelDB:超高性能kv存儲引擎

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Node.js","attrs":{}}],"attrs":{}},{"type":"text","text":"被設計用來做快速高效的網絡I/O。它的事件驅動流使其成爲一種智能代理的理想選擇,通常作爲後端系統和前端之間的粘合劑。Node的設計初衷就是爲了實現這一目的,但與此同時,它已成功用於構建傳統的Web應用程序:一個HTTP服務器,提供爲HTML頁面或JSON消息響應,並使用數據庫存儲數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"儘管其他平臺和語言有比較成熟的Web框架並更傾向於使用開源關係型數據庫,如MySQL或PostgreSQL,大多數Node Web框架(如Express、Hapi等)並不強制使用任何特定的數據庫,甚至根本不強制使用任何類型的數據庫。昨天在《","attrs":{}},{"type":"link","attrs":{"href":"https://www.devpoint.cn/article/276.shtml","title":"","type":null},"content":[{"type":"text","text":"淺談前端異常監控平臺實現方案","attrs":{}}]},{"type":"text","text":"》一文中就提到LevelDB,今天跟大家介紹這個超高性能的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Key-Value","attrs":{}}],"attrs":{}},{"type":"text","text":"數據庫LevelDB,同類型的比較流行的有MongoDB,本文暫不介紹MongoDB。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"認識LevelDB","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"LevelDB是Google傳奇工程師Jeff Dean和Sanjay Ghemawat開源的一款超高性能","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Key-Value","attrs":{}}],"attrs":{}},{"type":"text","text":"存儲引擎,以其驚人的讀性能和更加驚人的寫性能在輕量級","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"NoSql","attrs":{}}],"attrs":{}},{"type":"text","text":"數據庫中鶴立雞羣,此開源項目目前是支持處理十億級別規模","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Key-Value","attrs":{}}],"attrs":{}},{"type":"text","text":"型數據持久性存儲的C++ 程序庫。在優秀的表現下對於內存的佔用也非常小,大量數據都直接存儲在磁盤上,可以理解爲以空間換取時間。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"設計思路","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於普通機械磁盤順序寫的性能要比隨機寫高很多,而LevelDB的設計思想正是利用了磁盤的這個特性。 LevelDB的數據是存儲在磁盤上的,採用LSM-Tree的結構實現。LSM-Tree將磁盤的隨機寫轉化爲順序寫,從而大大提高了寫速度。爲了做到這一點LSM-Tree的思路是將索引樹結構拆成一大一小兩顆樹,較小的一個常駐內存,較大的一個持久化到磁盤,共同維護一個有序的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"key","attrs":{}}],"attrs":{}},{"type":"text","text":"空間。寫入操作會首先操作內存中的樹,隨着內存中樹的不斷變大,會觸發與磁盤中樹的歸併操作,而歸併操作本身僅有順序寫。如下圖所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f2/f24b0d78609b22ccbfadfbad6e130a93.jpeg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上圖爲 LevelDB 整體架構,靜態結構主要由六個部分組成:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"MemTable(wTable)","attrs":{}}],"attrs":{}},{"type":"text","text":":內存數據結構,具體實現是 SkipList。 接受用戶的讀寫請求,新的數據修改會首先在這裏寫入。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Immutable MemTable(rTable)","attrs":{}}],"attrs":{}},{"type":"text","text":":當 MemTable 的大小達到設定的閾值時,會變成 Immutable MemTable,只接受讀操作,不再接受寫操作,後續由後臺線程 Flush 到磁盤上。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"SST Files","attrs":{}}],"attrs":{}},{"type":"text","text":":Sorted String Table Files,磁盤數據存儲文件。分爲 Level0 到 LevelN 多層,每一層包含多個 SST 文件,文件內數據有序。Level0 直接由 Immutable Memtable Flush 得到,其它每一層的數據由上一層進行 Compaction 得到。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Manifest Files","attrs":{}}],"attrs":{}},{"type":"text","text":":Manifest 文件中記錄 SST 文件在不同 Level 的分佈,單個 SST 文件的最大、最小 key,以及其他一些 LevelDB 需要的元信息。由於 LevelDB 支持 snapshot,需要維護多版本,因此可能同時存在多個 Manifest 文件。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Current File","attrs":{}}],"attrs":{}},{"type":"text","text":":由於 Manifest 文件可能存在多個,Current 記錄的是當前的 Manifest 文件名。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Log Files (WAL)","attrs":{}}],"attrs":{}},{"type":"text","text":":用於防止 MemTable 丟數據的日誌文件。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"粗箭頭表示寫入數據的流動方向:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"先寫入 MemTable。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"MemTable 的大小達到設定閾值的時候,轉換成 Immutable MemTable。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"Immutable Table 由後臺線程異步 Flush 到磁盤上,成爲 Level0 上的一個 sst 文件。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"在某些條件下,會觸發後臺線程對 Level0 ~ LevelN 的文件進行 Compaction。","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"讀操作的流動方向和寫操作類似:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"讀 MemTable,如果存在,返回。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"讀 Immutable MemTable,如果存在,返回。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"按順序讀 Level0 ~ Leveln,如果存在,返回。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"返回不存在。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面就是簡單的介紹 LevelDB 的設計原理,架構和讀寫操作的數據流向,因爲獨特的設計原理,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"LevelDB很適合查詢較少,寫操作很多的場景","attrs":{}},{"type":"text","text":"。如果需要進一步瞭解其設計原理,就需要去學習跳躍表的設計算法,這裏就不展開了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"跳躍表是平衡樹的一種替代的數據結構,但是和紅黑樹不相同的是,跳躍表對於樹的平衡的實現是基於一種隨機化的算法的,這樣也就是說跳躍表的插入和刪除的工作是比較簡單的。","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"LevelDB特徵:","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"key和value都是任意長度的字節數組;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"存儲按鍵排序的數據;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"提供基本的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"put(key, value)","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"get(key)","attrs":{}}],"attrs":{}},{"type":"text","text":"和","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"delete(key)","attrs":{}}],"attrs":{}},{"type":"text","text":"接口;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"支持批量操作以原子操作進行;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以創建數據全景的snapshot(快照),並允許在快照中查找數據;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以通過前向(或後向)迭代器遍歷數據(迭代器會隱含的創建一個snapshot);","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"自動使用Snappy壓縮數據;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可移植性;","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於以上特性,很多區塊鏈項目都是採用LevelDB來作爲數據存儲。下面就開始介紹如何在項目中使用LevelDB,本文涉及的代碼在項目","attrs":{}},{"type":"link","attrs":{"href":"https://github.com/QuintionTang/pretender-service","title":"","type":null},"content":[{"type":"text","text":"Pretender-Service","attrs":{}}]},{"type":"text","text":"。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"安裝LevelDB","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"項目是基於Node.js,基礎環境就需要自己配置一下。執行一下命令:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"npm install level --save","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來還需要安裝","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"level-sublevel","attrs":{}}],"attrs":{}},{"type":"text","text":",爲了方便更好的使用LevelDB,不用自己設計分鍵空間。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"npm install level-sublevel --save","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還需要爲數據生成唯一ID的模塊,這裏我們安裝 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"cuid","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"npm install cuid --save","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"安裝完成後,將在應用程序中使用它,創建一個levelDb的類 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"./src/db/levelDb.js","attrs":{}}],"attrs":{}},{"type":"text","text":" :","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"添加引用的依賴庫","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"const level = require(\"level\");\nconst sublevel = require(\"level-sublevel\");","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在構造函數中聲明兩個變量,代碼如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"class LevelDb {\n constructor(dbPath, options = {}) {\n this.options = options;\n this.db = sublevel(level(dbPath, { valueEncoding: \"json\" }));\n }\n}\nmodule.exports = LevelDb;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這裏,創建了一個導出LevelDB數據庫的單例模塊。首先需要level模塊,並使用它來實例化數據庫,併爲其提供路徑 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dbPath","attrs":{}}],"attrs":{}},{"type":"text","text":" 。此路徑爲 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"LevelDB","attrs":{}}],"attrs":{}},{"type":"text","text":" 存儲數據文件的目錄路徑。此目錄專門用於 LevelDB ,可能在開始時不存在。在這裏定義的路徑爲外部聲明的時候傳入進來。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"valueEncoding","attrs":{}}],"attrs":{}},{"type":"text","text":" 定義了使用的值的格式爲 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"json","attrs":{}}],"attrs":{}},{"type":"text","text":",支持一下格式:","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"hex","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"utf8","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"base64","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"binary","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ascii","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"utf16le","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"添加LevelDB操作方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在來爲上面定義的類增加方法,常用的方法有 put、get、delete、batch、find。本文只是基本的操作,實際項目需要對數據進行合理的設計。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在構造函數中創建了LevelDB數據庫對象","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"this.db","attrs":{}}],"attrs":{}},{"type":"text","text":",可以調用其方法。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"put","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"新增或者更新數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":" put(key, value, callback) {\n if (key && value) {\n this.db.put(key, value, (error) => {\n callback(error);\n });\n } else {\n callback(\"no key or value\");\n }\n }","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"get","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"獲取指定key的數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":" get(key, callback) {\n if (key) {\n this.db.get(key, (error, value) => {\n callback(error, value);\n });\n } else {\n callback(\"no key\", key);\n }\n }","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"delete","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"刪除指定key的數據","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":" delete(key, callback) {\n if (key) {\n this.db.del(key, (error) => {\n callback(error);\n });\n } else {\n callback(\"no key\");\n }\n }","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"batch","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"LeveLDB的一個強大功能是,它允許對要自動執行的批處理中的操作進行分組。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":" batch(arr, callback) {\n if (Array.isArray(arr)) {\n var batchList = [];\n arr.forEach(item);\n {\n var listMember = {};\n if (item.hasOwnProperty(\"type\")) {\n listMember.type = item.type;\n }\n if (item.hasOwnProperty(\"key\")) {\n listMember.key = item.key;\n }\n if (item.hasOwnProperty(\"value\")) {\n listMember.value = item.value;\n }\n if (\n listMember.hasOwnProperty(\"type\") &&\n listMember.hasOwnProperty(\"key\") &&\n listMember.hasOwnProperty(\"value\")\n ) {\n batchList.push(listMember);\n }\n }\n if (batchList && batchList.length > 0) {\n this.db.batch(batchList, (error) => {\n callback(error, batchList);\n });\n } else {\n callback(\"array Membre format error\");\n }\n } else {\n callback(\"not array\");\n }\n }","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"到這裏已經完成一個 LevelDB 基礎操作類,下面就開始將其應用於項目中。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"使用LevelDB","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來創建一個","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"examples","attrs":{}}],"attrs":{}},{"type":"text","text":"的文件夾,增加文件","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"index.js","attrs":{}}],"attrs":{}},{"type":"text","text":",","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"key-value","attrs":{}}],"attrs":{}},{"type":"text","text":"數據庫存儲和關係型數據庫有所不一樣,關係型數據庫每條記錄一般都有一個唯一的自增長id,而","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"key-value","attrs":{}}],"attrs":{}},{"type":"text","text":"數據庫需要自己維護一個類似id的唯一key值,這個key值的設計也影響數據查詢是否遍歷。這裏我們只是做一個簡單的實例,完整代碼如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"\"use strict\";\nrequire(\"../src/utils/logger.js\")(2);\nconst { dbConfig } = require(\"../config\");\n\nconst LevelDB = require(\"../src/db/levelDb\");\nconst path = require(\"path\");\nconst cuid = require(\"cuid\");\nconst dbHelper = new LevelDB(\n path.resolve(__dirname, dbConfig.path, dbConfig.folder)\n);\n\n// 增加用戶信息\nconst administrators = [\n {\n name: \"QuintionTang\",\n email: \"[email protected]\",\n password: \"123456\",\n id: \"ckoyhjqbj0000mzkd1o63e31p\",\n },\n {\n name: \"JimGreen\",\n email: \"[email protected]\",\n password: \"123456\",\n id: \"ckoyhjqbk0001mzkdhuq9abo4\",\n },\n];\nconst keyPrefix = \"administrator\";\nconsole.info(\"====>開始插入數據\");\nconst administratorsKeys = [];\nfor (const item of administrators) {\n const uid = item.id;\n const keyName = `${keyPrefix}_${uid}`;\n item.id = uid;\n dbHelper.put(keyName, item, (error) => {\n if (error !== null) {\n administratorsKeys.push(keyName);\n }\n });\n}\nconsole.info(\"====>開始查找數據\");\n// 開始查找uid爲 ckoyhjqbj0000mzkd1o63e31p 的用戶信息\nconst findUid = \"ckoyhjqbj0000mzkd1o63e31p\";\nconst findKeyName = `${keyPrefix}_${findUid}`;\ndbHelper.find(\n {\n prefix: findKeyName,\n },\n (error, result) => {\n console.info(result);\n }\n);","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來執行實例代碼:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"cd examples\nnode index.js","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"執行結果如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f4/f48f9b65094ad33f9c4dbf20c1415dcf.jpeg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此時查看根目錄下 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"database","attrs":{}}],"attrs":{}},{"type":"text","text":" 就會生成數據庫文件。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文簡單介紹了LevelDB的設計原理,在項目中完成LevelDB類的定義,並實現一個簡單的數據插入和查詢。後續會在項目","attrs":{}},{"type":"link","attrs":{"href":"https://github.com/QuintionTang/pretender-service","title":"","type":null},"content":[{"type":"text","text":"Pretender-Service","attrs":{}}]},{"type":"text","text":"完成更加複雜的業務邏輯,實現基本的CURD,敬請關注項目動態。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章