ITPub博客

首页 > 数据库 > > BoltDB使用笔记

BoltDB使用笔记

作者:飘絮絮絮丶 时间:2022-03-09 16:11:12 0 删除 编辑

1、BoltDB简介

BoltDB官方文档如下:https://github.com/boltdb/bolt

BoltDB在Github上的说明:

Bolt是基于纯Go语言开发的KV存储,灵感来自于Howard Chu的LMDB项目。该项目目标是开发一个简单、快速、可靠的无服务端的数据库。API非常小巧和简洁,仅仅关注如何获取或设置数据,这就是全部。 BoltDB是K-V存储,没有关系型数据库中类似表、行、列结构,数据以key-value对存储(类似GO语言中的map) 。相似的key-value对存储在同一bucket中,类似于关系型数据库中的Table。因此,为了获取一个value,需要知道其所在的bucket以及对应的key。

2、BoltDB常用命令

BoltDB安装

直接在命令行使用以下命令:

1
$ go get github.com/boltdb/bolt/...

  

打开数据库:

1
db, err := bolt.Open("my.db", 0600, &bolt.Options{Timeout: 1 * time.Second})

读写数据库:
1
2
3
4
err := db.Update(func(tx *bolt.Tx) error {
    ...
    return nil
})

只读数据库:
1
2
3
4
err := db.View(func(tx *bolt.Tx) error {
    ...
    return nil
})

批量读写数据库:
1
2
3
4
err := db.Batch(func(tx *bolt.Tx) error {
    ...
    return nil
})

  

手动管理交易:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 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
}

  

使用buckets:

1
2
3
4
5
6
7
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
})

  

将key/value对写入Bucket:

1
2
3
4
5
db.Update(func(tx *bolt.Tx) error {
    b := tx.Bucket([]byte("MyBucket"))
    err := b.Put([]byte("answer"), []byte("42"))
    return err
})

  

从Bucket中获取value:

1
2
3
4
5
6
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
})

  

在bucket中设置自增整数变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// CreateUser saves u to the store. The new user ID is set on u once the data is persisted.
func (s *Store) CreateUser(u *User) error {
    return s.db.Update(func(tx *bolt.Tx) error {
        // Retrieve the users bucket.
        // This should be created when the DB is first opened.
        b := tx.Bucket([]byte("users"))
 
        // Generate ID for the user.
        // This returns an error only if the Tx is closed or not writeable.
        // That can't happen in an Update() call so I ignore the error check.
        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
    ...
}

  

根据key遍历:

1
2
3
4
5
6
7
8
9
10
11
12
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支持的操作方法:

1
2
3
4
5
First()  Move to the first key.
Last()   Move to the last key.
Seek()   Move to a specific key.
Next()   Move to the next key.
Prev()   Move to the previous key.

  

前缀扫描:

1
2
3
4
5
6
7
8
9
10
11
db.View(func(tx *bolt.Tx) error {
    // Assume bucket exists and has keys
    c := tx.Bucket([]byte("MyBucket")).Cursor()
 
    prefix := []byte("1234")
    for k, v := c.Seek(prefix); k != nil && bytes.HasPrefix(k, prefix); k, v = c.Next() {
        fmt.Printf("key=%s, value=%s\n", k, v)
    }
 
    return nil
})

  

区间扫描:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
db.View(func(tx *bolt.Tx) error {
    // Assume our events bucket exists and has RFC3339 encoded time keys.
    c := tx.Bucket([]byte("Events")).Cursor()
 
    // Our time range spans the 90's decade.
    min := []byte("1990-01-01T00:00:00Z")
    max := []byte("2000-01-01T00:00:00Z")
 
    // Iterate over the 90's.
    for k, v := c.Seek(min); k != nil && bytes.Compare(k, max) <= 0; k, v = c.Next() {
        fmt.Printf("%s: %s\n", k, v)
    }
 
    return nil
})

  

ForEach():

1
2
3
4
5
6
7
8
9
10
db.View(func(tx *bolt.Tx) error {
    // Assume bucket exists and has keys
    b := tx.Bucket([]byte("MyBucket"))
 
    b.ForEach(func(k, v []byte) error {
        fmt.Printf("key=%s, value=%s\n", k, v)
        return nil
    })
    return nil
})

  

数据库备份:

1
2
3
4
5
6
7
8
9
10
11
12
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="my.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)
    }
}

  

或者:

1
$ curl http://localhost/backup > my.db

  

统计:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
go func() {
    // Grab the initial stats.
    prev := db.Stats()
 
    for {
        // Wait for 10s.
        time.Sleep(10 * time.Second)
 
        // Grab the current stats and diff them.
        stats := db.Stats()
        diff := stats.Sub(&prev)
 
        // Encode stats to JSON and print to STDERR.
        json.NewEncoder(os.Stderr).Encode(diff)
 
        // Save stats for the next loop.
        prev = stats
    }
}()

  

只读模式:

1
2
3
4
db, err := bolt.Open("my.db", 0666, &bolt.Options{ReadOnly: true})
if err != nil {
    log.Fatal(err)
}

  

移动应用(iOS/Android):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func NewBoltDB(filepath string) *BoltDB {
    db, err := bolt.Open(filepath+"/demo.db", 0600, nil)
    if err != nil {
        log.Fatal(err)
    }
 
    return &BoltDB{db}
}
 
type BoltDB struct {
    db *bolt.DB
    ...
}
 
func (b *BoltDB) Path() string {
    return b.db.Path()
}
 
func (b *BoltDB) Close() {
    b.db.Close()
}

  

Android:

1
2
3
4
5
6
7
String path;
if (android.os.Build.VERSION.SDK_INT >=android.os.Build.VERSION_CODES.LOLLIPOP){
    path = getNoBackupFilesDir().getAbsolutePath();
} else{
    path = getFilesDir().getAbsolutePath();
}
Boltmobiledemo.BoltDB boltDB = Boltmobiledemo.NewBoltDB(path)

  

IOS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- (void)demo {
    NSString* path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
                                                          NSUserDomainMask,
                                                          YES) objectAtIndex:0];
    GoBoltmobiledemoBoltDB * demo = GoBoltmobiledemoNewBoltDB(path);
    [self addSkipBackupAttributeToItemAtPath:demo.path];
    //Some DB Logic would go here
    [demo close];
}
 
- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString
{
    NSURL* URL= [NSURL fileURLWithPath: filePathString];
    assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
 
    NSError *error = nil;
    BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
                                  forKey: NSURLIsExcludedFromBackupKey error: &error];
    if(!success){
        NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
    }
    return success;
}

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69946831/viewspace-3167356/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-09-09

  • 博文量
    2646
  • 访问量
    42234