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个先前的值(可选)。这可能通过实现指针版本控制来完成。
  • 事务支持,基本上缓冲指针更新并在原子性地写入。指针版本控制实现后,这将相对简单。
  • 极端形式的版本控制将是纯追加行为。
  • 支持有序遍历和简单查询的索引。可能是btreesplay-tree索引。
  • 支持IndexedDB API。
  • 可能实现一个STM服务器。

公开的API

底层存储引擎的接口基本上是一个简单的从Uint8ListUint8List的映射。

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

1 回复

更多关于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();
}
回到顶部