boltdb 學習和實踐

golang boltdb的學習和實踐

1. 安裝

go get github.com/boltdb/bolt

2.創建和啟動數據庫

db, err := bolt.Open("my.db", 0600, nil)

其中open的第一個參數為路徑,如果數據庫不存在則會創建名為my.db的數據庫, 第二個為文件操作,第三個參數是可選參數, 內部可以配置只讀和超時時間等,
特別需要注意的地方就是因為boltdb是文件操作類型的數據庫,所以只能單點寫入和讀取,如果多個同時操作的話后者會被掛起直到前者關閉操作為止, boltdb一次只允許一個讀寫事務,但一次允許多個只讀事務。所以數據具有較強的一致性。

因此單個事務和從它們創建的所有對象(例如桶、鍵)都不是線程安全的。與數據在多個概念你必須為每一個或使用鎖機制來保證只有一個goroutine里操作改變數據。
只讀事務和讀寫事物通常不應該在同一個goroutine里同時打開。由于讀寫事務需要周期性地重新映射數據文件,這可能導致死鎖。

3.讀寫事務

boltdb的讀寫事務操作我們可以使用DB.Update()來完成形如:

err := db.Update(func(tx *bolt.Tx) error {...return nil
})

在閉包fun中,在結束時返回nil來提交事務。您還可以通過返回一個錯誤在任何點回滾事務。所有數據庫操作都允許在讀寫事務中進行。
始終要關注err返回,因為它將報告導致您的事務不能完成的所有磁盤故障。

4.批量讀寫事物

每一次新的事物都需要等待上一次事物的結束,這種開銷我們可以通過DB.Batch()批處理來完成

err := db.Batch(func(tx *bolt.Tx) error {...return nil
})

在批處理過程中如果某個事務失敗了,批處理會多次調用這個函數函數返回成功則成功。如果中途失敗了,則整個事務會回滾。

5.只讀事務

只讀事務可以使用DB.View()來完成

err := db.View(func(tx *bolt.Tx) error {...return nil
})

不改變數據的操作都可以通過只讀事務來完成, 您只能檢索桶、檢索值,或在只讀事務中復制數據庫。

6.啟動事務

DB.Begin()啟動函數包含在db.update和db.batch中,該函數啟動事務開始執行事務并返回結果關閉事務,這是boltdb推薦的方式,有時候你可能需要手動啟動事物你可以使用Tx.Begin()來開始,切記不要忘記關閉事務。

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

7.使用桶

桶是數據庫中鍵/值對的集合。桶中的所有鍵必須是唯一的。您可以使用DB.CreateBucket()創建一個桶:

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

你也可以是實用Tx.CreateBucketIfNotExists()來創建桶,該函數會先判斷是否已經存在該桶不存在即創建, 刪除桶可以使用Tx.DeleteBucket()來完成

8.使用k-v對

存儲鍵值對到桶里可以使用Bucket.Put()來完成:

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

獲取鍵值Bucket.Get()

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

get()函數不返回一個錯誤,因為它的運行是保證工作(除非有某種系統故障)。如果鍵存在,那么它將返回它的值。如果它不存在,那么它將返回nil。
還需要注意的是當事務打開都get返回的值時唯一有效的,如果你需要將該值用于其他事務,你可以通過copy拷貝到其他的byte slice中

9.桶的自增

利用nextsequence()功能,你可以讓boltdb生成序列作為你鍵值對的唯一標識。見下面的示例。

func (s *Store) CreateUser(u *User) error {return s.db.Update(func(tx *bolt.Tx) error {// 創建users桶b := tx.Bucket([]byte("users"))// 生成自增序列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...
}

10. 迭代鍵

boltdb以桶中的字節排序順序存儲鍵。這使得在這些鍵上的順序迭代非常快。要遍歷鍵,我們將使用游標Cursor()

db.View(func(tx *bolt.Tx) error {// Assume bucket exists and has keysb := 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()  移動到第一個健.
Last()   移動到最后一個健.
Seek()   移動到特定的一個健.
Next()   移動到下一個健.
Prev()   移動到上一個健.

這些函數中的每一個都返回一個包含(key []byte, value []byte)的簽名。當你有光標迭代結束,next()將返回一個nil。在調用next()或prev()之前,你必須尋求一個位置使用first(),last(),或seek()。如果您不尋求位置,則這些函數將返回一個nil鍵。
在迭代過程中,如果鍵為非零,但值為0,則意味著鍵指向一個桶而不是一個值。用桶.bucket()訪問子桶。

11.前綴掃描

遍歷一個key的前綴,你可以結合seek()bytes.hasprefix()

db.View(func(tx *bolt.Tx) error {// Assume bucket exists and has keysc := tx.Bucket([]byte("MyBucket")).Cursor()prefix := []byte("1234")for k, v := c.Seek(prefix); bytes.HasPrefix(k, prefix); k, v = c.Next() {fmt.Printf("key=%s, value=%s\n", k, v)}return nil
})

12.范圍掃描

另一個常見的用例是掃描范圍,例如時間范圍。如果你使用一個合適的時間編碼,如rfc3339然后可以查詢特定日期范圍的數據:

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

13.循環遍歷每一個

如果你知道所在桶中擁有鍵,你也可以使用ForEach()來迭代:

db.View(func(tx *bolt.Tx) error {// Assume bucket exists and has keysb := tx.Bucket([]byte("MyBucket"))b.ForEach(func(k, v []byte) error {fmt.Printf("key=%s, value=%s\n", k, v)return nil})return nil
})

14.嵌套桶

還可以在一個鍵中存儲一個桶,以創建嵌套的桶:

func (*Bucket) CreateBucket(key []byte) (*Bucket, error)
func (*Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error)
func (*Bucket) DeleteBucket(key []byte) error

15.數據庫備份

boltdb是一個單一的文件,所以很容易備份。你可以使用TX.writeto()函數寫一致的數據庫。如果從只讀事務調用這個函數,它將執行熱備份,而不會阻塞其他數據庫的讀寫操作。
默認情況下,它將使用一個常規文件句柄,該句柄將利用操作系統的頁面緩存。有關優化大于RAM數據集的信息,請參見Tx文檔。
一個常見的用例是在HTTP上進行備份,這樣您就可以使用像cURL這樣的工具來進行數據庫備份:

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
或者你可以打開你的瀏覽器以http://localhost/backup,它會自動下載。
如果你想備份到另一個文件,你可以使用TX.copyfile()輔助功能。

16.統計

數據庫對運行的許多內部操作保持一個運行計數,這樣您就可以更好地了解發生了什么。通過捕捉這些數據的快照,我們可以看到在這個時間范圍內執行了哪些操作。
例如,我們可以開始一個goroutine里記錄統計每10秒:

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}

17.只讀模式

有時創建一個共享的只讀boltdb數據庫是有用的。對此,設置options.readonly國旗打開數據庫時。只讀模式使用共享鎖允許多個進程從數據庫中讀取,但它將阻塞任何以讀寫方式打開數據庫的進程。

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

18.移動端支持(ios/android)

boltdb能夠運行在移動設備上利用的工具結合特征GoMobile。創建一個結構體,包含您的數據庫邏輯和參考一個bolt.db與初始化contstructor需要在文件路徑,數據庫文件將存儲。使用這種方法,Android和iOS都不需要額外的權限或清理。

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

19.查看工具

1.下載工具
go get github.com/boltdb/boltd
然后編譯cmd下的main文件生成可執行文件改名為boltd
拷貝boltd到 *.db同級目錄,執行如下:
圖片描述
然后打開網站:
圖片描述

2.命令行工具
https://github.com/hasit/bolter
boltdb基礎學習暫時就這么多,下一章開始實踐

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/455815.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/455815.shtml
英文地址,請注明出處:http://en.pswp.cn/news/455815.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【django】使用django-crontab執行django自定義指令

django-crontab 部署 需求&#xff1a;再指定的時間內輸入django的自定義指令&#xff0c;來進行一些需求的操作。 使用流程: 1.安裝&#xff1a; pip install django-crontab 2.配置 settings.py文件: 再settings.py 文件中添加 django-crontab: INSTALLED_APPS (...django…

濾波問題匯總

1。A:JM86里面,GetStrength這個函數中下面這個數組有什么作用呢??byte BLK_NUM[2][4][4] {{{0,4,8,12},{1,5,9,13},{2,6,10,14},{3,7,11,15}},{{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}}} ;blk_y (mb_y<<2) (blkQ >> 2) ;blk_x (mb_x<<2)…

redis基本類型和使用

redis存儲數據的基本類型有&#xff1a;string&#xff08;字符串類型&#xff09;、hash&#xff08;散列類型&#xff09;、list&#xff08;列表類型&#xff09;、set&#xff08;集合類型&#xff09;、zset&#xff08;有序集合類型&#xff09;。 依次做一些練習。redis…

Python與MySQL數據庫連接

Python3 MySQL 數據庫連接 MySQL 可應用于多種語言&#xff0c;包括 PERL, C, C, JAVA 和 PHP 什么是 PyMySQL&#xff1f; PyMySQL 是在 Python3.x 版本中用于連接 MySQL 服務器的一個庫&#xff0c;Python2中則使用mysqldb。 PyMySQL 遵循 Python 數據庫 API v2.0 規范&a…

mysql 日志_MySQL日志系統

MySQL日志系統MySQL有兩個重要的日志系統&#xff0c;分別是 redo log (重做日志) 和 bin log (歸檔日志) 。這兩種日志有以下三點不同。redo log 是 InnoDB 引擎特有的&#xff1b;binlog 是 MySQL 的 Server 層實現的&#xff0c;所有引擎都可以使用。redo log 是物理日志&am…

盛大游戲杯第十五屆上海大學程序設計聯賽暨上海金馬五校賽

編程1小時&#xff0c;提交4小時 做這種比賽一定要選一個好OJ啊 黑白圖像直方圖 發布時間: 2017年7月8日 21:00 最后更新: 2017年7月8日 22:38 時間限制: 1000ms 內存限制: 128M 描述 在一個矩形的灰度圖像上&#xff0c;每個像素點或者是黑色的或者是白色的。黑色像素點…

對幾個重要問題的闡述

由于DPB中間的參考幀的MV都是以4X4塊為單位&#xff0c;現在以8X8塊作Direct mode模式&#xff0c;所以必須對子塊的MV作合并&#xff0c; JM采用的東西是如下圖的方式: x o | o x o o | o o - - - - - o o | o o x o | o x 每8X8塊取外角上的4X4塊的MV. 算法如下: <<<…

【MySQL】基于Docker的Mysql主從復制搭建

基于Docker的Mysql主從復制搭建 為什么基于Docker搭建&#xff1f; 資源有限 虛擬機搭建對機器配置有要求&#xff0c;并且安裝mysql步驟繁瑣 一臺機器上可以運行多個Docker容器 Docker容器之間相互獨立&#xff0c;有獨立ip&#xff0c;互不沖突 Docker使用步驟簡便&#xf…

Web開發介紹

Web開發介紹 一,認識一個網站 最早的軟件都是運行在大型機上的&#xff0c;軟件使用者通過“啞終端”登陸到大型機上去運行軟件。 后來隨著PC機的興起&#xff0c;軟件開始主要運行在桌面上&#xff0c;而數據庫這樣的軟件運行在服務器端&#xff0c;這種Client/Server模式簡…

python云端系統開發入門_Python云端系統開發入門

第01課 初識Django 課時1Django框架介紹 00 : 14 : 33 開始學習 課時2工程搭建1 00 : 28 : 50 開始學習 課時3工程搭建2 00 : 13 : 22 開始學習 第02課 請求和響應的處理 課時1獲取請求url的參數 00 : 07 : 57 開始學習 課時2獲取請求url的查詢字符串 00 : 12 : 01 開始學習 課…

IBM 安全部門 CTO:AI 必須被重新定義為“增強智能”

編者按&#xff1a;隨著人工智能的發展&#xff0c;人們對它逐漸有誤會、恐懼之心。如果能夠利用好人工智能&#xff0c;特別是在網絡安全領域&#xff0c;它將成為人類對抗網絡犯罪強有力的武器。IBM 安全部門的 CTO Sandy Bird 認為現在的人工智能應該被重新定義為“增強智能…

【Nginx】通過反向代理配置本地圖床功能

安裝nginx sudo apt-get install nginx配置nginx.conf sudo vim /etc/nginx/nginx.conf worker_processes auto; pid /run/nginx.pid;events {worker_connections 768;# multi_accept on; }http {sendfile on;tcp_nopush on;tcp_nodelay on;keepalive_timeout 65;types_hash…

構建之法第二章

單元測試&#xff1a;一個開發人員要面對測試一個單元時只給出單元的代碼而沒有規格說明這樣吃力不討好的任務.你怎樣做才會有更多的收獲,而不僅僅是發現編譯器的Bug?第一步是理解這個單元原本要做什么, --- 不是它實際上做了什么. 比較有效的方法是倒推出一個概要的規格說明.…

幀內預測模式提取

if (input->rdopt) { int mb_available_up; int mb_available_left; int mb_available_up_left; min_rdcost max_rdcost; // precompute all new chroma intra prediction modes // 對色度進行幀內預測 IntraChromaPredict…

Django簡介以及安裝

Django簡介 1. 認識Django Django是一個高級的Python Web框架&#xff0c;它鼓勵快速開發和清潔&#xff0c;務實的設計。由經驗豐富的開發人員構建&#xff0c;它負責Web開發的許多麻煩&#xff0c;因此您可以專注于編寫應用程序&#xff0c;而無需重新創建輪子。它是免費的…

python基礎筆試面試題_python基礎面試常見題

Python是目前市面上&#xff0c;我個人認為是最簡潔、最優雅、最有前途、最全能的編程語言&#xff0c;沒有之一。 2、通過什么途徑學習的Python&#xff1f; 通過自學&#xff0c;包括網上查看一些視頻&#xff0c;購買一些相關專業的書籍。 3、Python和Java、PHP、C、C#、C等…

django-rest-swagger顯示接口備注內容

Swagger是一個API開發者的工具框架&#xff0c;用於生成、描述、調用和可視化RESTful風格的Web服務。總體目標是使客戶端和文件系統服務器以同樣的速度來更新&#xff0c;方法&#xff0c;參數和模型緊密集成到服務器端的代碼中&#xff0c;允許API始終保持同步。 在使用 djan…

安全和連接是IoT聯網設備2大挑戰

IoT正在推動500億個聯網設備在未來10年內從工業、零售、智能照明、智慧城市、汽車、農業、可穿戴設備、智能建筑、醫療市場涌現出來&#xff0c;ARM處理器部門市場營銷總監Ian Smythe表示&#xff1a;“到2020年&#xff0c;消費電子和健康、智慧城市和物流、汽車和運輸領域的I…

windows下部署免費ssl證書(letsencrypt)

隨著網絡的發展&#xff0c;網絡安全也越來越重要&#xff0c;對于網站來說&#xff0c;從Http升級到https也是我們要做的首要事情。要實現https&#xff0c;首先我們需要申請一張SSL證書&#xff0c;這篇文章我主要介紹下邊這幾個方面&#xff1a; 1. SSL簡單介紹 2. 免費Lete…

Django之URLconf路由

URLconf路由 一個干凈優雅的URL方案是高質量Web應用程序中的一個重要細節。 Django可以讓你設計URL&#xff0c;無論你想要什么&#xff0c;沒有框架限制。 要為應用程序設計URL&#xff0c;您可以非正式地創建一個名為URLconf&#xff08;URL配置&#xff09;的Python模塊。…