BuntDB是纯Go开发的、低层级的(low-level)的、可嵌入的key/value内存数据库(IMDB),数据持久化存储,遵从ACID,支持自定义索引和地理空间 数据。BuntDB旨在给用户提供可靠稳定高效的数据库。
特点:
1.因为是内存数据库,所以支持快速的读和写
2.可采用简单的API,实现数据库嵌入功能
3.20维以下的空间索引;对地理空间数据有用
4.支持创建任何数据类型的自定义索引,JSON文档中的索引字段,支持多值索引;类似于SQL多列索引
5.支持String, Uint, Int, Float等内置类型,数据的灵活迭代;升序、降序和范围
6.紧密的代码库,在1K LOC使用CLOC命令
7.具有数据库的可靠性恢复和回滚机制,支持 ACID
用法:
1.安装buntdb数据库:go get -u github.com/tidwall/buntdb
2.引入buntdb数据库:import "github.com/tidwall/buntdb"
3.依据数据库路径打开数据库,没有则创建一个数据库:db, _ := buntdb.Open("data.db")
或者在内存建立一个临时数据库,不做持久化存储:db, _ := buntdb.Open(":memory:")
4.以只读模式读取数据库:
err := db.View(func(tx *buntdb.Tx) error {
...
return nil
})
以读写模式读取数据库:
err := db.Update(func(tx *buntdb.Tx) error {
...
return nil
})
5.以读写模式存储键值"mykey", "myvalue":
err := db.Update(func(tx *buntdb.Tx) error {
_, _, err := tx.Set("mykey", "myvalue", nil)
return err
})
以只读模式读取键"mykey"对应值,如果不存在键则返回错误ErrNotFound:
err := db.View(func(tx *buntdb.Tx) error {
val, err := tx.Get("mykey")
if err != nil{
return err
}
fmt.Printf("value is %s\n", val)
return nil
})
6.以只读模式迭代Ascend读取全部键值,同样还有AscendGreaterOrEqual, AscendLessThan, AscendRange, AscendEqual, Descend, DescendLessOrEqual, DescendGreaterThan, DescendRange, 和DescendEqual,具体用法查看文档:
err := db.View(func(tx *buntdb.Tx) error {
err := tx.Ascend("", func(key, value string) bool {
fmt.Printf("key: %s, value: %s\n", key, value)
})
return err
})
7.创建自定义索引,索引名name,*代表匹配任何格式,索引对应值排序为与大小写无关字母string排序:db.CreateIndex("names", "*", buntdb.IndexString)
插入索引和其对应的键值:
db.Update(func(tx *buntdb.Tx) error {
tx.Set("user:0:name", "tom", nil)
return nil
})
只读模式读取索引name对应的键值:
db.View(func(tx *buntdb.Tx) error {
tx.Ascend("names", func(key, val string) bool {
fmt.Printf(buf, "%s %s\n", key, val)
return true
})
return nil
})
只有具有前缀user:的键的项才会添加到名称索引中:db.CreateIndex("names", "user:*", buntdb.IndexString)
8.除了indexstring之外,还有indexint、indexuint和indexfloat。这些是用于索引的内置类型。因此,要创建一个以数字顺序排列在年龄键上的索引,我们可以使用:
db.CreateIndex("ages", "user:*:age", buntdb.IndexInt)
添加值:
db.Update(func(tx *buntdb.Tx) error {
tx.Set("user:0:age", "35", nil)
return nil
})
读取值,输出结果年龄数字从小到大排序:
db.View(func(tx *buntdb.Tx) error {
tx.Ascend("ages", func(key, val string) bool {
fmt.Printf(buf, "%s %s\n", key, val)
return true
})
return nil
})
9.创建空间位置索引,例如索引fleet对应结构"fleet:*:pos"经纬度矩形值:db.CreateSpatialIndex("fleet", "fleet:*:pos", buntdb.IndexRect),该IndexRect函数使用不同的格式进行渲染,例如众所周知的文本或geojson。
插入经纬度
db.Update(func(tx *buntdb.Tx) error {
tx.Set("fleet:0:pos", "[-115.567 33.532]", nil)
return nil
})
Intersects函数读取 "[-117 30],[-112 36]"对应矩形内的值:
db.View(func(tx *buntdb.Tx) error {
tx.Intersects("fleet", "[-117 30],[-112 36]", func(key, val string) bool {
...
return true
})
return nil
})
Nearby函数,由 "[-113 33]"近到远排序读取值:
db.View(func(tx *buntdb.Tx) error {
tx.Nearby("fleet", "[-113 33]", func(key, val string, dist float64) bool {
...
return true
})
return nil
})
10.创建json格式索引last_name,按照last进行排序:db.CreateIndex("last_name", "*", buntdb.IndexJSON("name.last"))
插入json格式键值:
db.Update(func(tx *buntdb.Tx) error {
tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38}`, nil)
return nil
})
读取last_name对应键值,以last属性进行升序排序:
db.View(func(tx *buntdb.Tx) error {
fmt.Println("Order by last name")
tx.Ascend("last_name", func(key, value string) bool {
fmt.Printf("%s: %s\n", key, value)
return true
})
return nil
})
11.使用buntdb,可以在一个索引上联接多个值。这类似于传统SQL数据库中的多列索引。
在本例中,我们在“name.last”和“age”上创建多值索引,即先进行last排序,若相同再进行age排序:db.CreateIndex("last_name_age", "*", buntdb.IndexJSON("name.last"), buntdb.IndexJSON("age"))
12.Buntdb当前不支持在迭代过程中删除密钥。作为解决方法,您需要在迭代器完成后删除键:
var delkeys []string
tx.AscendKeys("object:*", func(k, v string) bool {
if someCondition(k) == true {
delkeys = append(delkeys, k)
}
return true // continue
})
for _, k := range delkeys {
if _, err = tx.Delete(k); err != nil {
return err
}
}
13.关闭数据库:defer db.Close()
示例源码:阅读原文,用法文档:https://godoc.org/github.com/tidwall/buntdb#ex-package--DescKeys
希望大家关注我的微信公众号,日更一篇区块链技术博客不易,有疑问可以后台留言。