BoltDB官方文檔以下:https://github.com/boltdb/boltandroid
BoltDB在Github上的說明:git
Bolt是基於純Go語言開發的KV存儲,靈感來自於Howard Chu的LMDB項目。該項目目標是開發一個簡單、快速、可靠的無服務端的數據庫。API很是小巧和簡潔,僅僅關注如何獲取或設置數據,這就是所有。 BoltDB是K-V存儲,沒有關係型數據庫中相似表、行、列結構,數據以key-value對存儲(類似GO語言中的map) 。類似的key-value對存儲在同一bucket中,相似於關係型數據庫中的Table。所以,爲了獲取一個value,須要知道其所在的bucket以及對應的key。github
BoltDB安裝數據庫
直接在命令行使用如下命令:json
$ go get github.com/boltdb/bolt/...
打開數據庫:
app
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 })
手動管理交易:curl
// 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:oop
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:ui
db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("MyBucket")) err := b.Put([]byte("answer"), []byte("42")) return err })
從Bucket中獲取value:url
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中設置自增整數變量:
// 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\n", 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\n", 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\n", 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\n", 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; }