zoukankan      html  css  js  c++  java
  • BoltDB使用笔记

    1、BoltDB简介

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

    BoltDBGithub上的说明:

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

    2、BoltDB常用命令

    BoltDB安装

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

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

      

    打开数据库:

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

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

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

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

      

    手动管理交易:

    // 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:

    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:

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

      

    从Bucket中获取value:

    db.View(func(tx *bolt.Tx) error {
    	b := tx.Bucket([]byte("MyBucket"))
    	v := b.Get([]byte("answer"))
    	fmt.Printf("The answer is: %s
    ", v)
    	return nil
    })
    

      

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

    // 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遍历:

    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
    ", k, v)
    	}
    
    	return nil
    })
    

      

    cursor支持的操作方法:

    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.
    

      

    前缀扫描:

    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
    ", k, v)
    	}
    
    	return nil
    })
    

      

    区间扫描:

    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
    ", k, v)
    	}
    
    	return nil
    })
    

      

    ForEach():

    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
    ", k, v)
    		return nil
    	})
    	return nil
    })
    

      

    数据库备份:

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

      

    或者:

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

      

    统计:

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

      

    只读模式:

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

      

    移动应用(iOS/Android):

    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:

    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:

    - (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;
    }
    

      








  • 相关阅读:
    2020面试阿里,字节跳动90%被问到的JVM面试题
    mysql数据库误删恢复
    因用了Insert into select语句,公司报警了
    Spring的Controller是单例还是多例?怎么保证并发的安全
    SpringBoot项目优化和Jvm调优
    java从一个pdf中取出指定页生成一个新的pdf
    java截取出字符串中的所有组数字
    oracle表空间位置迁移
    solr常用操作及集成分词器或cdh集群部署说明
    Oracle中将列查询结果多行逗号拼接成一个大字段
  • 原文地址:https://www.cnblogs.com/yxdz-hit/p/8536094.html
Copyright © 2011-2022 走看看