bolt是一个纯go语言实现的键值数据库,支持完全的ACID实务操作,尽管不像SQLite那样有完善的查询语言,但是接口简单易用。bolt本身通过使用一个内存映射的磁盘文件来管理数据,逻辑清晰,接口简单易用。下面代码就是bolt提供的简单的操作接口示例。
db, err := bolt.Open("example.db", 0600, nil)
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 当传递的函数中返回了error,bolt将会自动的执行
// rollback操作,不需要手动执行任何操作
err := db.Update(func(tx *bolt.Tx) error{
// ...
})
// 只读的实务操作定义在db.View函数中,仅仅可以读取
// 和迭代数据
err := db.View(func(tx *bolt.Tx)error{
// ...
})
bolt设计灵感来源于LMDB(一个轻量级的内存映射数据库)。LMDB本身可以提供高性能的读操作和线程安全的写入操作,并且支持ACID实务操作,bolt早期仅仅打算做成一个Go版本的LMDB,但是如今已得到越来越多的关注github的star数量也突破了7000。
一些常见的关系数据库,比如MySQL以及Postgres这些数据库,提供对于结构化数据的存储以及SQL语句的支持,可以灵活的查询和存储数据来满足业务的需求,但是解析和处理SQL层也会带来很大的开销。bolt所有的数据访问都是通过键来完成,基于B+树存储结构的设计使得读写数据效率较高。同时常规数据库往往与程序分离部署,通过网络序列化完成传递,也会增加一部分处理延迟和降低处理效率。bolt通过一个文件来存储数据,尽管访问问题上不是足够灵活,但是效率较高。
LevelDB,也属于一个键值数据库,Google开源C++语言实现。提供一个排序的数据存储结构,但是不支持实务操作,通过LSM树来存储键值数据到,支持高效的随机写入但是对于读取效率不高,特别是当数据的容量越来越大的时候。如果对于读取效率要求比较高,可以考虑使用bolt来进行测试。 ·
Bolt的键值数据对存储在一个有序的map结构中,由于是有序的因此可以获得稳定的迭代数据,另外bolt定义了bucket的结构,类似于一堆键的集合或者类似于数据库的表,另外可以在bucket中存储其他的buckets。如下是一个简单的存储和查询的流程
err = db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte("posts"))
if err != nil {
return err
}
return b.Put([]byte("2017-11-20"), []byte("new post"))
})
err = db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("posts"))
v := b.Get([]byte("2017-11-20"))
fmt.Printf("%s", v)
return nil
})
如果需要存储一个复杂的数据结构比如自定义的结构体数据则需要调用一些序列化的函数来获得编码后的数据存储,比如使用json.Marshal来编码:
type User struct {
Name string `json:"name"`
Address string `json:"address"`
Age int `json:age`
}
…
err = db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte("users"))
if err != nil {
return err
}
encoded, err := json.Marshal(user)
if err != nil {
return err
}
return b.Put([]byte(user.Name), encoded)
})
err = db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("users"))
v := b.Get([]byte("mike"))
user := new(User)
err := json.Unmarshal(v, user)
if err != nil {
return err
}
fmt.Printf("%+v", user)
return nil
})
另外bolt提供命令行工具来完成对于数据库状态的检查和测试。
Usage:
bolt command [arguments]
The commands are:
bench run synthetic benchmark against bolt
check verifies integrity of bolt database
compact copies a bolt database, compacting it in the process
info print basic info
help print this screen
pages print list of pages with their types
stats iterate over all pages and generate usage stats
bolt尽管API比较简单,但是实现较为优雅,很多大的企业在内部使用bolt来存储一些业务数据。如果有一些对于读要求较为高的应用可以考虑测试一下bolt的使用效果。
另外注意的是:对于bolt来说存储的文件由于是内存映射的对象存储内容,因此是大小端敏感的,可能会导致拷贝到特定的机器上不能正常使用。不过大部分的用户使用现代的CPU来说是小端存储,因此问题不大。