Boltdb学习笔记之〇--概述

简介: Boltdb学习笔记之〇--概述

看了Boltdb也有一阵子了,看完之后总想写点什么,因为感觉到这可能是个不小的坑,所以迟迟没有动笔(没错我的拖延症又犯了..)。最近有一种流行的说法:如果一个东西不能把它讲清楚,便不能说你学会了它。


因为看起来会和真的会之间有一个巨大的鸿沟,想跨越这个鸿沟便需要不断的提问、思考与输出,这是个相对枯燥但绝对值得的过程,因此趁着周末两天的完整时间正式开始挖坑。




什么是boltdb


Boltdb是一个go语言开发的嵌入式kv数据库。其实现相对简单:


  • 不支持网络请求和SQL查询,因此也就没有了网络交互、词法分析、语法分析、查询优化等成熟数据库中必不可少的功能。


  • 使用了比较少见的shadow page技术,只支持一个writer和多个reader,在这种约束下,事务的隔离级别为可串行话,并发控制也比较简单


  • 使用mmap将内存与磁盘建立映射,由OS管理磁盘page load到内存的过程,大大减少了boltdb手动管理的复杂度。


Boltdb所有代码加起来才1W行,但是麻雀虽小五脏俱全,非常适合用来学习数据库中的一些基本原理和概念,例如page、transanction、cursor等。


值得一提的是,Boltdb还是etcd底层的kv存储,目前Boltdb原仓库(https://github.com/boltdb/bolt)已经是read-only状态。而etcd维护了一个fork(https://github.com/etcd-io/bbolt), 主要是为了继续增强可靠性、稳定性和性能。




如何使用boltdb


数据模型



在使用boltdb之前,我们需要对其数据模型有个直观的了解。以下是boltdb与关系型数据库的数据模型简单类比:


boltdb中的概念 关系型数据库中的概念
DB database
Bucket table
key value pair Tuple

Boltdb中的Bucket虽然可简单类比成关系型数据中table,有一点却不相同:前者可嵌套创建Bucket, 即一个Bucket下还可创建子Bucket, 而后者不行。


安装


go get github.com/boltdb/bolt/...


操作DB


操作DB包括创建(打开)、关闭。

代码如下:在执行bolt.Open时,如果指定文件路径不存在,则根据路径创建一个数据库文件;否则加载该路径下的文件。使用db.Close便可关闭DB.


package main  
import (  
 "log"  
 "github.com/boltdb/bolt"  
)  
func main() {  
 // Open the my.db data file in your current directory.  
 // It will be created if it doesn't exist.  
 db, err := bolt.Open("my.db", 0600, nil)  
 if err != nil {  
  log.Fatal(err)  
 }  
 defer db.Close()  
 ...  
}



操作事务


Boltdb中按照是否只读将事务分为读事务和写事务。

用户使用db.View创建读事务时需传入一个回调函数,表示读事务执行操作。如果回调函数返回的err != nildb.View则会回滚该事务,并将err透传给db.View


err := db.View(func(tx *bolt.Tx) error {  
 ...  
 return nil  
})


使用db.Update可创建写事务。db.Update如何处理错误同db.View


err := db.Batch(func(tx *bolt.Tx) error {  
 ...  
 return nil  
})


操作Bucket


操作Bucket包括创建Bucket、删除Bucket


创建Bucket属于写事务。这里db.Update会创建一个写事务,写事务执行的操作是CreateBucket,即创建一个新的Bucket


db.Update(func(tx *bolt.Tx) error {  
 b, err := tx.CreateBucket([]byte("MyBucket"))  
 if err != nil {  
  return fmt.Errorf("create bucket: %s", err)  
 }  
 return nil  
})


删除Bucket也属于写事务。使用上同理


db.Update(func(tx *bolt.Tx) error {  
 b, err := tx.DeleteBucket([]byte("MyBucket"))  
 if err != nil {  
  return fmt.Errorf("create bucket: %s", err)  
 }  
 return nil  
})


操作key/value


操作key/value包括:新建/更新/删除/查询。所有的key/value对都必须属于某个具体的Bucket. 因此操作key/value之前必须找到Bucket对象。


新建/更新代码必须用写事务封装,代码如下,这里在名为MyBucket的Bucket下新增了一对("answer", "42")


db.Update(func(tx *bolt.Tx) error {  
 b := tx.Bucket([]byte("MyBucket"))  
 err := b.Put([]byte("answer"), []byte("42"))  
 return err  
})


删除代码如下:


db.Update(func(tx *bolt.Tx) error {  
 b := tx.Bucket([]byte("MyBucket"))  
 err := b.Delete([]byte("answer")  
 return err  
})


查询代码如下:


db.View(func(tx *bolt.Tx) error {  
 b := tx.Bucket([]byte("MyBucket"))  
 v := b.Get([]byte("answer"))  
 fmt.Printf("The answer is: %s\n", v)  
 return nil  
})




如何分析Boltdb


代码导读


首先是读代码,从微观到宏观的层面了解这座房屋如何建成的。代码阅读顺序是


page.go: 磁盘上的page layout,包括meta page, freelist page, branch page, leaf page。  
node.go: 磁盘上的page反序列化到内存之后的数据结构,也作为B+树节点。  
freelist.go: page管理, 支持page申请、释放、回滚等操作。  
cursor.go: 用于访问B+树的迭代器  
bucket.go: Bucket数据结构,支持创建/删除子Bucket、新建/更新/删除kv数据。  
db.go.go: 用于访问DB, 支持打开/关闭DB、创建读/写事务、db file自动扩容。


更详细的代码细节将在该系列的后续内容中给出.


分析工具



Boltdb提供了一个好用的工具,可用于查看db file中每个page的内容


安装:

git clone https://github.com/boltdb/bolt   
cd cmd/bolt  
go build  
ls ./bolt


查看所有pages状态


$ ./bolt  pages  /tmp/bolt.db   | head  
ID       TYPE       ITEMS  OVRFLW  
======== ========== ====== ======  
0        meta       0              
1        meta       0              
2        freelist   4              
3        leaf       141            
4        leaf       86             
5        leaf       85             
6        branch     117            
7        leaf       85


其中ID表示page id, TYPE为page类型,ITEMS表示其中的数据条数,OVRFLW表示该

page是否溢出。


查看某个page的内容


$ ./bolt  page /tmp/bolt-624750664  3  | head  
Page ID:    3  
Page Type:  leaf  
Total Size: 4096 bytes  
Item Count: 141  
"9874": "9874"  
"9875": "9875"  
"9876": "9876"  
"9877": "9877"  
"9878": "9878"


以上为某个leaf page的内容,底部为该page中存储的key/value对。

相关文章
|
存储 消息中间件 缓存
键值(key-value)数据库
【4月更文挑战第9天】键值数据库(NoSQL)以键值对形式存储数据,简单灵活,适合任意类型数据。其特点是高性能、高可扩展性,常见应用包括缓存、会话管理、分布式锁、计数统计、配置管理和轻量级消息队列。然而,它不适用于结构化信息存储和复杂查询,选择时需考虑应用场景。
2128 5
|
21天前
|
人工智能 自然语言处理 搜索推荐
AI数字人技术力盘点:数字人平台技术实力、产品实测、市场口碑综合推荐
2025年,AI数字人爆发:克拉玛依“小克”上线,罗永浩数字人6小时带货5500万。IDC数据显示,中国AI数字人市场规模2024年达41.2亿元,增速85.3%。世优科技以全栈技术打造1200+数字人IP,赋能政务、文旅等场景;科大讯飞依托语音优势,让“数字大圣”多语互动;微软小冰聚焦明星IP,孵化洛天依等虚拟偶像。从技术深耕到IP运营,三巨头各展所长,推动数字人从概念走向规模化落地,重塑商业未来。
96 0
|
12月前
|
安全 数据挖掘 数据安全/隐私保护
国产CRM品牌巡礼:系统品牌的核心优势与特色
本文深度解析国产CRM系统的四大知名品牌:销售易、神州云动、销帮帮和天衣云。 销售易:中国领先的CRM解决方案提供商,提供全渠道获客、智能化销售流程及AIGC技术应用,赢得500强企业信赖。 神州云动:以PaaS+SaaS模式、灵活定制和行业解决方案著称,支持企业实现客户关系管理的数字化和智能化。 销帮帮:面向中小企业的实用型CRM系统,提供销售跟踪、客户视图等功能,提高销售效率和客户满意度。 天衣云:专注于云端部署,提供快速部署、高安全性的CRM解决方案,确保企业信息安全。 各品牌各有特色,企业应根据自身需求选择合适的CRM系统,以实现客户关系的全面管理,提升业务效率和客户满意度。
|
11月前
|
敏捷开发 监控 数据可视化
敏捷开发的6大方法与模型,帮助你快速适应项目需求变化
3分钟了解6种常见的敏捷开发方法,包括Scrum,看板Kanban,极限编程(XP),DSDM、特征驱动开发和水晶法等方法。
1624 5
敏捷开发的6大方法与模型,帮助你快速适应项目需求变化
|
数据采集 Python
Selenium爬取百度热搜榜单
Selenium爬取百度热搜榜单
340 1
Selenium爬取百度热搜榜单
|
Kubernetes 负载均衡 监控
在K8S中,各组件是如何实现高可用?
在K8S中,各组件是如何实现高可用?
|
监控 安全 JavaScript
对跨站脚本攻击(XSS)的防御策略?
【8月更文挑战第15天】
1351 1
|
XML Java 决策智能
拥抱智能决策新纪元!Spring Boot携手LiteFlow规则引擎,让复杂业务处理如丝般顺滑,引领技术潮流!
【8月更文挑战第29天】LiteFlow是一款专为Java应用设计的轻量级规则引擎,支持条件、循环、分支等多种规则类型,具有组件化设计和高度可扩展性。通过自定义规则和事件监听,它可以显著提升代码的可维护性和可重用性。本文将详细介绍如何在Spring Boot项目中整合LiteFlow,并通过实际案例演示其强大功能。主要步骤包括:添加依赖、配置参数、定义组件及流程,并通过API触发执行。借助LiteFlow,复杂业务逻辑处理变得更加灵活高效。
707 0
|
API 开发者 Windows
pywin32
pywin32
392 3
|
存储 Go
善用这些技巧 Go语言map元素删除那么简单
善用这些技巧 Go语言map元素删除那么简单
3476 0