Flutter数据库管理插件libdbm的使用
Flutter数据库管理插件libdbm的使用
简介
这是libdbm.dart
,一个类似于dbm
的数据库的dart实现。它极其简单且极其快速。为了便于使用,除了较低级别的API外,还提供了dart Map
接口的实现。此Map
接口可以在适当的序列化参数下持久化任何数据。像许多其他基于dbm
的系统一样,它使用哈希方法提供了一个非常快的键值存储。它有意设计得非常精简,并且没有依赖项。
这是一个早期预览版。将添加额外的功能,包括维护多个键上的索引的能力和支持IndexedDB
API。
开始使用
该API故意极其简单。要使用此库,需要导入包,打开数据库并存储/检索值。
持久化Map
使用PersistentMap
接口与使用普通Map非常相似,尽管数据存储在磁盘上。所有常规的Map
接口都得到支持,除了cast()
操作。
import 'dart:io';
import 'package:libdbm/libdbm.dart';
void main() {
final file = File('dummy.db');
var db = PersistentMap.withStringValue(file, create:true);
// 持久化
db['foo'] = 'bar';
var result = db['foo'];
print('$result');
db.remove('foo');
db.close();
file.delete();
}
PersistentMap
实现不会覆盖已存在的数据库,但会在指定create:true
时创建新数据库。
原始DBM/HashDBM
此API是最底层的API,PersistentMap
就是基于此构建的。它在功能上非常相似,但需要一些额外的工作才能使用。
import 'dart:io';
import 'dart:convert' show utf8;
import 'package:libdbm/libdbm.dart';
void main() {
final key = utf8.encoder.convert('A key');
final value = utf8.encoder.convert('A value');
final file = File('dummy.db');
final db = HashDBM(file.openSync(mode: FileMode.write));
db.put(key, value);
var result = db.get(key);
print('${utf8.decode(result!.toList())}');
for (var i = db.entries(); i.moveNext();) {
print('${utf8.decode(i.current.key)}');
print('${utf8.decode(i.current.value)}');
}
db.remove(key);
db.get(key); // 将返回null
db.close();
file.delete();
}
注意,要打开已关闭的数据库,请使用FileMode.append
,否则旧数据将被覆盖(这是一种截断数据库的简单方法)。
性能
基准测试是出了名的困难,但作为一个大致的指导原则,libdbm
哈希存储能够在每秒处理数千个键值对。以下数字来自测试套件中的10,000对。
桶数 | 操作 | 时间 |
---|---|---|
103 | 插入 | 0:00:05.483791 |
103 | 查询 | 0:00:02.668405 |
1009 | 插入 | 0:00:03.275287 |
1009 | 查询 | 0:00:01.393490 |
10007 | 插入 | 0:00:00.371533 |
10007 | 查询 | 0:00:00.126720 |
100003 | 插入 | 0:00:00.126404 |
100003 | 查询 | 0:00:00.059652 |
可以看到,性能的一个主要因素是内部哈希表的大小。这将在调用flush()
或close()
时持久化到外部存储,并通常会消耗16*num
字节。一般来说,将其设置为较大的素数是好的。
其他主要因素是是否启用了flush
,它会强制将基于内存的数据结构写入磁盘。还可以向记录添加CRC校验,这将大致减半吞吐量(即操作将花费两倍的时间);
空间和内存使用
数据库文件格式有一些固定和动态大小的开销。一般来说,静态开销小于1K。动态开销是哈希表和内存池所需的大小(大约每个条目16字节),然后是每条记录约32字节的开销,记录对齐到128字节边界。因此,存储大量小值的开销会相对较高,最好将这些值聚合到单个记录中。相反,存储较大值(如文本或JSON数据)的开销则相对较低。
限制
当前最大的限制与健壮性有关。该库尚未支持事务,虽然已经采取了一些措施确保可靠性,但该库不使用WAL(Write-Ahead Logging),所以在极端情况下,可能会有很小的机会发生损坏。最好的缓解方式是启用flush
。还需要编写更多的测试来处理不良输入等,但该库经过了充分测试,并已在生产中使用。
目前,哈希表的大小是固定的,但文件格式支持重新哈希/重新分配哈希表。未来将利用这一能力自动优化性能。
计划增强
- 值的版本控制,以便保留
n
个先前的值(可选)。这可能通过实现指针版本控制来完成。 - 事务支持,基本上缓冲指针更新并在原子性地写入。指针版本控制实现后,这将相对简单。
- 极端形式的版本控制将是纯追加行为。
- 支持有序遍历和简单查询的索引。可能是
btree
和splay-tree
索引。 - 支持
IndexedDB
API。 - 可能实现一个STM服务器。
公开的API
底层存储引擎的接口基本上是一个简单的从Uint8List
到Uint8List
的映射。
abstract class DBM {
Uint8List? get(Uint8List key);
Uint8List? remove(Uint8List key);
Uint8List? put(Uint8List key, Uint8List value);
Uint8List putIfAbsent(Uint8List key, Uint8List value);
Iterator<MapEntry<Uint8List,Uint8List>> entries();
DateTime modified();
int version();
int size();
int count();
void clear();
void flush();
void close();
}
更多关于Flutter数据库管理插件libdbm的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter数据库管理插件libdbm的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
libdbm
是一个用于 Flutter 的数据库管理插件,它提供了一个简单的键值存储接口,类似于其他键值存储系统(如 SharedPreferences
)。libdbm
使用 Dart 编写,并且支持跨平台(iOS、Android、Web、Linux、macOS、Windows)。
安装 libdbm
首先,你需要在 pubspec.yaml
文件中添加 libdbm
依赖:
dependencies:
flutter:
sdk: flutter
libdbm: ^1.0.0
然后运行 flutter pub get
来安装依赖。
使用 libdbm
1. 初始化数据库
在使用 libdbm
之前,你需要初始化一个数据库实例。你可以使用 DBM
类来创建一个数据库实例。
import 'package:libdbm/libdbm.dart';
void main() async {
// 初始化数据库
var db = await DBM.open('my_database.db');
// 使用数据库
// ...
// 关闭数据库
await db.close();
}
2. 存储数据
你可以使用 put
方法将数据存储到数据库中。put
方法接受一个键和一个值。
await db.put('key1', 'value1');
await db.put('key2', 42);
await db.put('key3', true);
3. 获取数据
你可以使用 get
方法从数据库中获取数据。get
方法接受一个键,并返回与该键关联的值。
var value1 = await db.get('key1'); // 'value1'
var value2 = await db.get('key2'); // 42
var value3 = await db.get('key3'); // true
4. 删除数据
你可以使用 delete
方法从数据库中删除数据。delete
方法接受一个键。
await db.delete('key1');
5. 遍历所有键值对
你可以使用 forEach
方法遍历数据库中的所有键值对。
await db.forEach((key, value) {
print('Key: $key, Value: $value');
});
6. 关闭数据库
当你不再需要数据库时,应该关闭它以释放资源。
await db.close();
示例代码
以下是一个完整的示例,展示了如何使用 libdbm
进行简单的数据库操作:
import 'package:libdbm/libdbm.dart';
void main() async {
// 初始化数据库
var db = await DBM.open('my_database.db');
// 存储数据
await db.put('key1', 'value1');
await db.put('key2', 42);
await db.put('key3', true);
// 获取数据
var value1 = await db.get('key1'); // 'value1'
var value2 = await db.get('key2'); // 42
var value3 = await db.get('key3'); // true
print('Value1: $value1');
print('Value2: $value2');
print('Value3: $value3');
// 删除数据
await db.delete('key1');
// 遍历所有键值对
await db.forEach((key, value) {
print('Key: $key, Value: $value');
});
// 关闭数据库
await db.close();
}