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.mzph.cn/news/455815.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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;每个像素点或者是黑色的或者是白色的。黑色像素点…

Web开发介绍

Web开发介绍 一,认识一个网站 最早的软件都是运行在大型机上的&#xff0c;软件使用者通过“哑终端”登陆到大型机上去运行软件。 后来随着PC机的兴起&#xff0c;软件开始主要运行在桌面上&#xff0c;而数据库这样的软件运行在服务器端&#xff0c;这种Client/Server模式简…

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…

python中什么是关键字参数_如何使用python语言中函数的关键字参数的用法

一般情况下&#xff0c;在调用函数时&#xff0c;使用的是位置参数&#xff0c;即是按照参数的位置来传值&#xff1b;关键字参数是按照定义函数传入的参数名称来传值的。那么&#xff0c;关键字参数怎么使用&#xff1f;工具/原料 python pycharm 截图工具 WPS 方法/步骤 1 打…

【SSL】HTTPS配置全过程

服务器配置https协议 HTTPS&#xff0c;是以安全为目标的HTTP通道&#xff0c;简单讲是HTTP的安全版。即HTTP下加入SSL层&#xff0c;HTTPS的安全基础是SSL&#xff0c;因此加密的详细内容就需要SSL。 配置HTTPS就需要证书&#xff0c;关于证书方面不做过多解释&#xff0c;只…

输出四位完全平方数_完全平方数中的规律

PS&#xff1a;很近之前自己收集的资料一个正整数如果是另一个整数的完全平方&#xff0c;那么我们就称这个数为完全平方数&#xff0c;也叫做平方数。如&#xff1a;0&#xff0c;1&#xff0c;4&#xff0c;9&#xff0c;16&#xff0c;25&#xff0c;36&#xff0c;49&#…

为企业提供本地销售人员的Universal Avenue获1000万美元A轮融资

为各类B2B企业提供本地销售人员的瑞典初创企业Universal Avenue近日获得了1000万美元的A轮融资。此轮融资由Eight Roads&#xff08;富达国际的投资机构&#xff09;领投&#xff0c;原有投资者Northzone和MOOR跟投&#xff0c;加上2015年获得的500万美元种子轮融资&#xff0c…

【Linux分享】Linux常用命令+教程分享

今天分享分为两部分 :) PART01 Linux常用命令分享/ PART02 关于BD面试经验分享 30mins Linux Command: PART 1 你本可以张口就来..... 本篇内容分享的宗旨: 拿下Linux面试 别面试的时候呆呆地说个ls了&#x1f691; 本篇分享详细地介绍了常用Linux指令的功能、语法、参…

万能无线鼠标对码软件_400元就能买ROG无线游戏鼠标,ROG影刃2无线版使用体验...

影刃2是ROG刚刚推出的一款新产品&#xff0c;定位入门游戏玩家。目前市面上定位入门游戏玩家的无线鼠标真不多&#xff0c;400块以内的预算想要选购一款合适的无线游戏鼠标&#xff0c;选择其实非常有限。 就ROG产品线而言&#xff0c;烈刃2的价格到了700块钱&#xff1b;罗技G…

wampserver 虚拟主机

转载&#xff1a;http://blog.csdn.net/knight_quan/article/details/51830683 1.背景&#xff1a; 在进行网站开发的时候&#xff0c;通常需要以http://localhost或者127.0.0.1等地址来访问本地环境的网站。不过随着开发项目的增多&#xff0c;需要每次先访问localhost然后再选…

PL/SQL的结构

2019独角兽企业重金招聘Python工程师标准>>> [DECLARE] --声明开始关键字/*这里是声明部分,包括PL/SQL中的变量、常量以及类型第等*/BEGIN --执行部分开始标志/*这里是执行部分,是整个PL/SQL块的主体部分,该部分必须存在,可以是SQL语句或流程控制语句等…

cf方框透视易语言代码怎么写_易语言真的那么不入流吗?

很多人鄙视易语言&#xff0c;为什么那么多人一提易语言&#xff0c;除了骂&#xff0c;还是骂&#xff0c;易语言很大错误吗&#xff1f;知乎上的大神们是这么说的一个语言的“入流”&#xff0c;和是不是英文关键字无关&#xff0c;而是和这种语言进入某一子行业的契机有关。…

python发展历程

作者&#xff1a;Vamei 出处&#xff1a;http://www.cnblogs.com/vamei 欢迎转载&#xff0c;也请保留这段声明。谢谢&#xff01; Python是我喜欢的语言&#xff0c;简洁&#xff0c;优美&#xff0c;容易使用。前两天&#xff0c;我很激昂的向朋友宣传Python的好处。 听过之…

【Django】RBAC权限管理系统模块-理解

今天文章分为两部分 :) PART1 RBAC权限管理内容分享/ PART2 关于字节跳动一面 10 Minutes Django-RBAC: PART 1 这权限管理系统主要功能是什么&#xff1f; 顾名思义&#xff0c;在系统中可以灵活的划分角色组&#xff0c;可以根据功能特性来划分&#xff1a;- 比如设置系…

Linux使用circos

1.在conda中安装bioconda conda install -c bioconda circos -y # 测试是否所有的module都安装好了 circos -module # 所有都显示OK则成功 ok 0.39 Font::TTF::Font ok 2.68 GD ok 0.2 GD::Polyline ... .... 2.检查模块是否齐全 circos -module 3.下…