golang bolt库操作手册

今天介绍的库bolt是一个纯粹用go编写的key/value数据库,这个库的目的是为了提供一个简单,快速可靠的数据库同时无需单独安装一个例如Postgres或MySQL之类的负责的数据库服务。作者在介绍里面还提及了如何通过阅读代码来了解一个数据库的基本原理,感谢作者的无私奉献。

打开数据库

package main

import (
    "os"

    "github.com/boltdb/bolt"
    "github.com/go-kit/kit/log"
)

func main() {
    logger := log.NewLogfmtLogger(os.Stdout)
    db, err := bolt.Open("mydb.db", 0600, nil)
    if err != nil {
        logger.Log("open", err)
    }
    defer db.Close()
}

Bolt在打开数据库文件的时候会获取一个文件锁,所以多个进程不能同时打开一个数据库文件。
打开一个已经Open的Bolt数据库会导致当前进程挂起直到其他进程关闭该Bolt数据库。
为了避免无限等待你可以在打开数据库文件的时候制定一个超时时间。

func worker() {
    logger := log.NewLogfmtLogger(os.Stdout)
    db, err := bolt.Open("kes.db", 0600, &bolt.Options{Timeout: 1 * time.Second})
    if err != nil {
        logger.Log("open", err)
        return
    }
    db.Close()
}

func main() {
    logger := log.NewLogfmtLogger(os.Stdout)
    db, err := bolt.Open("kes.db", 0600, &bolt.Options{Timeout: 1 * time.Second})
    if err != nil {
        logger.Log("open", err)
        return
    }
    defer db.Close()

    go worker()

    time.Sleep(10 * time.Second)
}

如上面代码所示,main函数中打开kes.go后另起一个routine打开同样的数据库文件,就会阻塞直到超时:

$ go run bolt.go
open=timeout

Transactions

Bolt数据库同时只支持一个read-write transaction或者多个read-only transactions。
每个独立的transaction以及在这个transaction中创建的所有对象(buckerts,keys等)都不是thread safe的。如果要在多个routine中处理数据,那么必须在每个routine中单独使用一个transaction或者显式的使用lock以确保在每个时刻只有一个routine访问这个transaction.

read-only的transaction和read-write的transaction不应该相互之间有依赖,一般来说在同一个goroutine中不要同时打开这两种transaction,因为read-write transaction需要周期性的re-map数据文件,但是由于read-only transaction打开导致read-write transaction的re-map操作无法进行造成死锁。

Read-write transactions

通过DB.UPdate()打开一个read-write transaction.

    if err := db.Update(func(tx *bolt.Tx) error {
        if _, err := tx.CreateBucketIfNotExists([]byte("kes")); err != nil {
            logger.Log("create failed", err)
            return err
        }
        return nil
    }); err != nil {
        logger.Log("update", err)
    }

在closure闭包内部,获取一个数据库的连续view。在closure最后返回nil完成commit的操作,可以在任何地方通过返回error完成rolleback的操作。
在read-write transaction中允许所有的数据库操作

func (db *DB) Update(fn func(*Tx) error) error {
    t, err := db.Begin(true)
    if err != nil {
        return err
    }

    // Make sure the transaction rolls back in the event of a panic.
    defer func() {
        if t.db != nil {
            t.rollback()
        }
    }()

    // Mark as a managed tx so that the inner function cannot manually commit.
    t.managed = true

    // If an error is returned from the function then rollback and return error.
    err = fn(t)
    t.managed = false
    if err != nil {
        _ = t.Rollback()
        return err
    }

    return t.Commit()
}

Read-Only transactions

通过 DB.View()函数打开一个read-only transaction。

    if err := db.View(func(tx *bolt.Tx) error {
        // if _, err := tx.CreateBucket([]byte("kes")); err != nil {
        //  logger.Log("create failed", err)
        //  return err
        // }
        return nil
    }); err != nil {
        logger.Log("view", err)
    }

在read-only transaction中不允许更改操作。只能获取buckets,查询value,复制数据库。
上面的代码中,如果把注释掉的代码加上,就会报错

view="tx not writable"
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值