一、簡介
BoltDB是一個純Go語言編寫的可嵌入式數據庫,它的數據被組織成一個B+樹的結構,用於提供高效、可靠的本地數據存儲服務。Bolt採用了MVCC(多版本並發控制)的處理方式,從而可以支持同時進行多個事務並發讀寫操作,而不是像一些其他的數據庫採用的加鎖方式。
Bolt的特徵有:支持ACID事務;鍵值對數據存儲方式;可排序查詢結果;支持內存映射的文件方式進行存儲;完全兼容Go的並發操作。
二、BoltDB的基本操作
1、打開和關閉數據庫的連接:
db, err := bolt.Open("mydb.db", 0600, nil) if err != nil { log.Fatal(err) } defer db.Close()
2、增加或更新數據:
db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte("MyBucket")) if err != nil { return err } err = b.Put([]byte("hello"), []byte("world")) return err })
3、查詢數據:
db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("MyBucket")) v := b.Get([]byte("hello")) fmt.Printf("value=%s\n", v) return nil })
4、刪除數據:
db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("MyBucket")) err := b.Delete([]byte("hello")) return err })
三、BoltDB的索引和排序
BoltDB支持對數據進行索引和排序,我們可以在創建數據桶時通過設置BucketOption來實現索引和排序。例如:
options := bolt.DefaultOptions options.NooSync = true options.NoFreelistSync = true db, err := bolt.Open("my.db", 0600, options) if err != nil { log.Fatal(err) } defer db.Close() db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte("MyBucket")) if err != nil { return err } // 創建索引 c := b.Cursor() for k, v := c.First(); k != nil; k, v = c.Next() { b2, err := tx.CreateBucketIfNotExists([]byte("IndexBucket")) if err != nil { return err } if err := b2.Put(v, k); err != nil { return err } } // 創建排序 c2 := b.Cursor() var keys [][]byte for k, _ := c2.First(); k != nil; k, _ = c2.Next() { keys = append(keys, k) } sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i], keys[j]) < 0 }) return nil })
四、BoltDB的事務處理
在Bolt中,所有的寫操作都需要在一個事務中進行。當我們使用db.Update()方法時,這個方法會創建一個新的只寫事務,以此來執行我們的修改操作,同時我們也可以執行讀操作,但是需要注意的是,讀操作只能讀取到事務開始時的那個快照。
如果我們需要進行只讀操作,我們要使用db.View()方法,這個方法會創建一個只讀事務,其能夠讀取到最近的已提交快照。
db, err := bolt.Open("my.db", 0600, nil) if err != nil { log.Fatal(err) } defer db.Close() // 開始寫入事務 db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte("MyBucket")) if err != nil { return err } // 添加數據 if err := b.Put([]byte("apple"), []byte("red")); err != nil { return err } // 添加數據 if err := b.Put([]byte("banana"), []byte("yellow")); err != nil { return err } return nil }) // 開始讀取事務 db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("MyBucket")) v := b.Get([]byte("apple")) fmt.Printf("value=%s\n", v) return nil })
五、BoltDB的性能測試
我們來對Bolt進行一次性能測試:
package main import ( "fmt" "log" "time" "github.com/boltdb/bolt" ) func main() { // 打開BoltDB db, err := bolt.Open("my.db", 0600, nil) if err != nil { log.Fatal(err) } defer db.Close() // 寫入1000000條數據 start := time.Now() db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte("MyBucket")) if err != nil { return err } for i := 0; i < 1000000; i++ { key := fmt.Sprintf("key-%d", i) value := []byte("value") if err := b.Put([]byte(key), value); err != nil { return err } } return nil }) end := time.Now() fmt.Printf("寫入1000000條數據,用時:%v\n", end.Sub(start)) // 讀取1000000條數據 start = time.Now() db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("MyBucket")) for i := 0; i < 1000000; i++ { key := fmt.Sprintf("key-%d", i) _ = b.Get([]byte(key)) } return nil }) end = time.Now() fmt.Printf("讀取1000000條數據,用時:%v\n", end.Sub(start)) }
執行結果如下:
寫入1000000條數據,用時:5.1054857s 讀取1000000條數據,用時:125.025682ms
我們可以看到,Bolt在寫入1000000條數據時使用5秒左右,而讀取1000000條數據則只需要125毫秒,這表明Bolt在進行數據的讀取及存儲時有着非常好的性能表現。
原創文章,作者:OTXD,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/142263.html