首页 > 数据库 > > 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。
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/ ,如需转载,请注明出处,否则将追究法律责任。