bbold是一个嵌入式的kv存储,作为主程序的lib库存在,提供简单可靠的get、set
github
boltdb当前api已经固定了,另外生产环境上一直在使用,数据存储量高达1T,所以值得信赖。另外代码量比较少(< 5k),适合用于研究。
import bolt "go.etcd.io/bbolt"
db, err := bolt.Open(path, 0666, nil)
if err != nil {
return err
}
defer db.Close()
db上的操作是goroutine safe的
//read-write transaction
err := db.Update(func(tx *bolt.Tx) error {
...
return nil
})
//read-only transaction
err = db.View(func(tx *bolt.Tx) error {
...
return nil
})
err := db.Batch(func(tx *bolt.Tx) error {
...
return nil
})
Concurrent Batch calls are opportunistically combined into larger transactions. Batch is only useful when there are multiple goroutines calling it.
batch可以随机合并多个goroutine的update操作,避免每个update带来的sync开销
batch有可能重试,所以需要是放入batch执行的函数需要时幂等的
bucket相当于一个namespace,一个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
})
db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("MyBucket"))
err := b.Put([]byte("answer"), []byte("42"))
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
})
get返回的byte slice使用的底层数组可能会改变,如果需要保存get的结果,需要copy一份
db.View(func(tx *bolt.Tx) error {
// Assume bucket exists and has keys
b := tx.Bucket([]byte("MyBucket"))
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
fmt.Printf("key=%s, value=%s\n", k, v)
}
return nil
})
During iteration, if the key is non-nil but the value is nil, that means the key refers to a bucket rather than a value. Use Bucket.Bucket() to access the sub-bucket.
bucket是可以嵌套的