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":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章