boltdb使用

1. boltDB 简介

BoltDB 是一个 使用 Golang 开发的 Key/Value 模型的程序,为不需要完整数据库服务器(如 MySQL)的项目提供一个简单,快速,可靠的数据库。
只需要将 BoltDB 链接到应用程序代码中即可使用它提供的 API 来存取数据,无需数据库管理语言。BoltDB 支持完全可序列化的 ACID 事务,可以处理复杂操作。

通过COW技术,可实现无锁的读写并发,但是无法实现无锁的写写并发,这就注定了读性能超高,但写性能一般,适合与读多写少的场景。

boltDB 安装

需要事先安装好 Go 环境

go get github.com/boltdb/bolt

这条命令会把类库包源代码,下载解压到你的 %GOPATH% 路径里面去,并且它还会同时执行 go install xxx ,生成 包路径

没有设置go mod会默认下载到%GOPATH%的src下,设置了会下载到%GOPATH%里pkg的mod下

在代码中导入第三方包

import ("github.com/boltdb/bolt")

打开数据库示例

func main() {
 db, err := bolt.Open("my.db", 0600, nil)  //打开数据库文件 如果没有则创建
 if err != nil { log.Fatal(err) }
 defer db.Close() ...  //关闭数据库
}

2. 基本操作

更新事务,该操作会被当做一个事务来处理,如果 Update() 内的操作返回nil,则事务会原子性被提交,返回错误则事务会回滚  

err := db.Update(func(tx *bolt.Tx) error {   //读写事件  当写操作是必须是update
    ...
    return nil
})

只读事务,可以进行数据查询操作

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

启动事务

DB.Begin()启动函数包含在db.update和db.batch中,该函数开始执行事务并返回结果关闭事务,这是boltdb推荐的方式,有时候你可能需要手动启动事物你可以使用Tx.Begin()来开始,切记不要忘记关闭事务。

// Start a writable transaction.
tx, err := db.Begin(true)
if err != nil {
    return err
}
defer tx.Rollback()
 
// Use the transaction...
_, err := tx.CreateBucket([]byte("MyBucket"))
if err != nil {
    return err
}
 
// Commit the transaction and check for error.
if err := tx.Commit(); err != nil {
    return err
}

创建桶

CreateBucket()    或者 CreateBucketIfNotExists()     建议使用后者如果桶存在则不进行操作

err = db.Update(func(tx *bolt.Tx) error {   //读写事务
        _, err := tx.CreateBucketIfNotExists([]byte(bucketname))  //根据视图名字创建   如果不存在则创建
        if err != nil {
            return fmt.Errorf("create bucket: %v", err)
        }
        fmt.Printf("%s已经存在",bucketname)
        return nil
    })
    if err != nil {
        log.Fatal(err)
    }

删除桶

DeleteBucket()    删除桶时里面的键值对数据也会被删除

err = db.Update(func(tx *bolt.Tx) error {   //读写事务
        b := tx.Bucket([]byte(bucketname))  //打开视图
        if b == nil {
            panic("你打开的视图不存在 请重新输入")
        }
        er:=tx.DeleteBucket([]byte(bucketname))
        if er != nil {  //异常处理
            defer func() {
                if r := recover(); r != nil {
                    fmt.Println(r)
                }
            }()
            panic("删除失败")
        }
        return nil
    })
    if err != nil {
        log.Fatal(err)
    }

Put  设置

存取键值对到桶里     以[]byte存取需转换   如果这个桶下的key已经存在则value会被替换

err = db.Update(func(tx *bolt.Tx) error {
        b := tx.Bucket([]byte(bucket))  //打开视图
        if b == nil {
            //异常处理
            defer func() {
                if r := recover(); r != nil {
                    fmt.Println(r)
                }
            }()
            panic("你打开的视图不存在 请重新输入")
        }
        // put 数据库插入 
        if err = b.Put([]byte(key), []byte(value)); err != nil {
            return err
        }
        return err
    })

Get   查询

从桶里获取键值对

db.View(func(tx *bolt.Tx) error {
        b := tx.Bucket([]byte(bucket))  //打开视图
        if b == nil {
            //异常处理
            defer func() {
                if r := recover(); r != nil {
                    fmt.Println(r)
                }
            }()
            panic("你打开的视图不存在 请重新输入")
        }
        v := b.Get([]byte(key))  // Get查询 key为answer的value
        res=string(v)      //转换为string
        //_ := b.Cursor()
        //fmt.Printf(" value=%s\n", v)
        return nil
    })

Delete 删除

 从桶里删除键值对

err = db.Update(func(tx *bolt.Tx) error {
        b := tx.Bucket([]byte(bucket))  //打开视图
        if b == nil {
            //异常处理
            defer func() {
                if r := recover(); r != nil {
                    fmt.Println(r)
                }
            }()
            panic("你打开的视图不存在 请重新输入")
        }
        // Delete  删除
        if err = b.Delete([]byte(key)) ; err != nil {
            fmt.Println("你要删除的key不存在")
            return err
        }

遍历Bucket

boltdb以桶中的字节排序顺序存储键。这使得在这些键上的顺序迭代非常快。要遍历键,我们将使用游标Cursor():

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
})

游标Cursor()允许您移动到键列表中的特定点,并一次一个地通过操作键前进或后退。

光标上有以下函数:

First()  移动到第一个键.

Last()   移动到最后一个键.

Seek()   移动到特定的一个键.

Next()   移动到下一个键.

Prev()   移动到上一个键.

可以自己组合游标封装需要的函数

利用游标实现前缀扫描

函数经过封装   可以前缀查找这个桶下以key开头的所有key-value   存储到map中

func KeyHeadGetValue(bucket string,keyhead string,mymap map[string]string){

	dbptr.View(func(tx *bolt.Tx) error {
		// Assume bucket exists and has keys
		c := tx.Bucket([]byte(bucket)).Cursor()
		prefix := []byte(keyhead)  //把byte序列化
		for k, v := c.Seek(prefix); bytes.HasPrefix(k, prefix); k, v = c.Next() {
			fmt.Printf("key=%s, value=%s\n", k, v)
			mymap[string(k)]=string(v)
		}
		return nil
	})
}

桶的自增

利用nextsequence()功能,你可以让boltdb生成序列作为你键值对的唯一标识。

func (s *Store) CreateUser(u *User) error {
    return s.db.Update(func(tx *bolt.Tx) error {
        // 创建users桶
        b := tx.Bucket([]byte("users"))
        // 生成自增序列
        id, _ = b.NextSequence()
        u.ID = int(id)
        // Marshal user data into bytes.
        buf, err := json.Marshal(u)
        if err != nil {
            return err
        }
        // Persist bytes to users bucket.
        return b.Put(itob(u.ID), buf)
    })
}

// itob returns an 8-byte big endian representation of v.
func itob(v int) []byte {
    b := make([]byte, 8)
    binary.BigEndian.PutUint64(b, uint64(v))
    return b
}

type User struct {
    ID int
    ...
}

数据库备份

boltdb是一个单一的文件,所以很容易备份。你可以使用TX.writeto()函数写一致的数据库。如果从只读事务调用这个函数,它将执行热备份,而不会阻塞其他数据库的读写操作。

默认情况下,它将使用一个常规文件句柄,该句柄将利用操作系统的页面缓存。有关优化大于RAM数据集的信息,请参见 Tx文档。
一个常见的用例是在HTTP上进行备份,这样您就可以使用像 cURL这样的工具来进行数据库备份:

 

func BackupHandleFunc(w http.ResponseWriter, req *http.Request) {
err := db.View(func(tx *bolt.Tx) error {
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", `attachment; filename="data.db"`)
w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size())))
_, err := tx.WriteTo(w)
return err
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
然后可以使用此命令进行备份:
$ curl http://localhost/backup > data.db
或者你可以打开你的浏览器以 http://localhost/backup,它会自动下载。
如果你想备份到另一个文件,你可以使用 TX.copyfile()辅助功能。

 TX.copyfile()实现备份和恢复

func Dbbackup(){
    db,err:=bolt.Open("./data.db", 0666, nil)
    if err!=nil{
        log.Fatal(err)
    }
    defer db.Close()   //关闭数据库连接
    err=db.View(func(tx *bolt.Tx) error {
        //备份db文件,第一个参数path表示备份文件路径,第二个参数mode表示备份文件的操作方式,值参考Linux下文件的-rwxrwxrwx权限
        err := tx.CopyFile("kstor.db",0666)
        return err
    })
    if err!=nil{
        panic("备份失败  ")
    }
}

查看工具

下载查看工具

go get github.com/boltdb/boltd

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值