Flutter数据库管理插件dart_lmdb2的使用
Flutter数据库管理插件dart_lmdb2的使用
dart_lmdb2
是一个用于Dart应用程序的高性能嵌入式数据库,它封装了LMDB(Lightning Memory-Mapped Database)。此包提供了高级便利方法和细粒度的事务控制。
Linux | Windows | Android | MacOS | iOS | web |
---|---|---|---|---|---|
💙 | 💙 | 💙 | 💙 | 💙 | - |
注意:所有平台的预编译本机二进制文件都包含在Dart包内,但iOS/Android需要Flutter才能在移动设备上运行。请参阅flutter_lmdb2。
为什么选择LMDB?
LMDB特别适合移动和嵌入式应用,原因如下:
-
移动友好设计:
- 数据库格式可在所有平台上移植。
- 通过内存映射和最少的I/O操作实现节能。
- 不需要后台进程或服务。
- 可配置的映射大小确保可预测的内存使用。
- 延迟数据加载实现快速应用启动。
-
资源需求最小:
- 超紧凑的本地库(小于150KB)。
- 固定映射大小限制的可配置数据库上限。
- 单线程设计,几乎无进程开销。
- 无需额外的运行时依赖。
-
卓越性能:
- 零拷贝读取通过直接内存映射。
- 高效的操作系统级页面缓存消除I/O瓶颈。
- 通过直接内存访问优化读取操作。
- 读事务不会阻塞写操作。
- 写操作不会阻塞读操作。
- 由于B+树设计,顺序读取非常快。
-
可靠性:
- 完整的ACID合规性,保证原子性和崩溃恢复。
- 写时复制设计确保数据库完整性,即使在崩溃后也是如此。
- 直接页更新,无需单独的日志文件。
- 可选的自包含单文件设计简化备份操作。
- 在OpenLDAP中经过实战测试。
为什么不选择LMDB?
LMDB不是通用数据库。它适用于特定用途,并在此类领域中表现出色。如果你有以下需求,则不应使用LMDB:
- 如果你的模式不是基于键值对,而是关系型的。
- 如果你需要高效地查询除键之外的值。
- 如果你想要保存时间序列或流数据(如日志记录)。
- 如果无法为写入场景提供与数据库大小相同数量的RAM。
场景
-
快速查询大数据库,同时占用少量内存,例如:
- 字典
- 瓷砖缓存
- 纹理缓存
- 多平台资产
-
实时数据的一致更新
- 生产者 -> 消费者
- 主应用 -> 插件实例
- 音频引擎 -> 可视化器
- 多个生产者 -> 多个消费者
- 工作池
- 分布式处理
- 资源受限的IPC
- Flutter应用 -> AudioUnit扩展
- 宿主 -> 沙箱插件
- 生产者 -> 消费者
-
配置数据(大量)
支持的功能
以下LMDB功能已暴露:
- 完整的CRUD操作
- 用于数据组织的命名数据库
- 游标操作用于范围查询
- 全面的事务支持,具有ACID保证
- 丰富的统计和监控
- 使用所有LMDB标志进行可配置初始化
LMDB版本
该包捆绑了LMDB版本 0.9.70
。虽然此版本号在过去三年内未更改,但LMDB仍在积极维护。我们跟踪的是确切的git仓库版本:da9aeda。
开始使用
将包添加到你的 pubspec.yaml
文件中:
dependencies:
dart_lmdb2: ^0.9.5
然后运行:
# 对于Dart项目:
dart pub get
# 对于Flutter项目:
flutter pub get
使用
导入并使用:
import 'package:dart_lmdb2/lmdb.dart';
void main() async {
final db = LMDB();
await db.init('path/to/db');
// 自动事务操作
await db.putAuto('key', 'value'.codeUnits);
final result = await db.getAuto('key');
// 手动事务控制
final txn = await db.txnStart();
try {
await db.put(txn, 'key1', 'value1'.codeUnits);
await db.put(txn, 'key2', 'value2'.codeUnits);
await db.putUtf8(txn, 'english_greeting', 'Hello World');
await db.txnCommit(txn);
} catch (e) {
await db.txnAbort(txn);
rethrow;
}
}
使用 LMDBInitConfig
配置数据库设置:
final config = LMDBInitConfig(
mapSize: 10 * 1024 * 1024, // 10MB
maxDbs: 1,
envFlags: 0,
mode: 0664,
);
await db.init('path/to/db', config: config);
开发
所有本地库都已包含在目录 lib/src/native
中:
lib/src/native/
├── android
│ ├── arm64-v8a
│ │ └── liblmdb.so
│ └── x86_64
│ └── liblmdb.so
├── ios
│ └── liblmdb.a
├── linux
│ └── liblmdb.so
├── macos
│ └── liblmdb.dylib
└── windows
└── lmdb.dll
你可以通过以下步骤重建这些库:
前提条件
该包捆绑了LMDB以从源代码构建。构建过程是自动化的,但需要:
- CMake(3.10 或更高版本)
- C 编译器(gcc、clang 或 MSVC)
- Dart SDK(3.0 或更高版本)
平台特定设置
Android
需要安装Android NDK,最好通过Android Studio。此外,需要设置环境变量 ANDROID_NDK_HOME
指向适当的NDK位置。
iOS / iPadOS / MacOS
请安装XCode和XCode命令行工具。
# 安装构建工具
brew install cmake
Linux
# 安装构建工具
sudo apt-get install build-essential cmake
Windows
- 安装Visual Studio,包含C++开发工具
- 安装CMake
构建和测试
- 克隆仓库并切换到项目子目录:
git clone https://github.com/grammatek/dart_lmdb2.git
cd dart_lmdb2/dart_lmdb2
- 安装依赖项:
dart pub get
- (可选)通过
ffigen
重新生成绑定:
dart run ffigen
- 构建本地库:
dart run tool/build.dart
对于Android,需要传递 --android
标志:
dart run tool/build.dart --android
对于iOS/iPadOS,需要传递 --ios
标志:
dart run tool/build.dart --ios
- 运行当前平台的测试:
dart test
示例代码
以下是使用 dart_lmdb2
的示例代码:
import 'package:dart_lmdb2/lmdb.dart';
import 'package:path/path.dart' as path;
import 'dart:io';
void main() async {
// 使用自定义配置初始化数据库
final config = LMDBInitConfig(
mapSize: 10 * 1024 * 1024, // 10MB
maxDbs: 1,
mode: "0664",
);
final dbPath = path.join(Directory.current.path, 'example_db');
final db = LMDB();
try {
await db.init(dbPath, config: config);
// 自动事务操作
await db.putAuto('key1', 'Hello World!'.codeUnits);
final result = await db.getAuto('key1');
if (result != null) {
print('Retrieved: ${String.fromCharCodes(result)}');
}
// 单个事务中的多个操作
final txn = await db.txnStart();
try {
await db.put(txn, 'key2', 'Transaction'.codeUnits);
await db.put(txn, 'key3', 'Example'.codeUnits);
final stats = await db.stats(txn);
print('\nDatabase Statistics:');
print('- Total Entries: ${stats.entries}');
print('- Tree Depth: ${stats.depth}');
print('- Leaf Pages: ${stats.leafPages}');
await db.txnCommit(txn);
} catch (e) {
await db.txnAbort(txn);
rethrow;
}
// 自动事务删除
await db.deleteAuto('key1');
// 验证删除
final deletedResult = await db.getAuto('key1');
print(
'\nAfter deletion: ${deletedResult == null ? 'Entry removed' : 'Entry still exists'}');
} finally {
db.close();
// 清理示例数据库
if (Directory(dbPath).existsSync()) {
Directory(dbPath).deleteSync(recursive: true);
}
}
}
更多关于Flutter数据库管理插件dart_lmdb2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter数据库管理插件dart_lmdb2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用dart_lmdb2
插件进行数据库管理的示例代码。dart_lmdb2
是一个用于与Lightning Memory-Mapped Database (LMDB)交互的Dart库,非常适合高性能的嵌入式数据库需求。
首先,确保你已经在pubspec.yaml
文件中添加了dart_lmdb2
依赖:
dependencies:
flutter:
sdk: flutter
dart_lmdb2: ^latest_version # 请替换为实际的最新版本号
然后,运行flutter pub get
来获取依赖。
接下来,让我们编写一些代码来展示如何使用dart_lmdb2
进行基本的数据库操作,如打开数据库环境、创建事务、存储和检索数据。
import 'package:dart_lmdb2/dart_lmdb2.dart';
import 'dart:typed_data';
import 'dart:convert';
void main() async {
// 设置数据库环境路径
String path = './testdb';
// 打开数据库环境
final env = await MdbEnv.create(path);
await env.setMaxReaders(1);
await env.setMapSize(1024 * 1024 * 1024); // 设置最大数据库大小(1GB)
// 开启一个读写事务
final txn = await env.beginTxn(write: true);
// 打开数据库(如果不存在则创建)
final dbi = await txn.openDbi('mydb', create: true);
// 要存储的数据(键值对)
String keyStr = 'key1';
String valueStr = 'value1';
Uint8List key = Uint8List.fromList(utf8.encode(keyStr));
Uint8List value = Uint8List.fromList(utf8.encode(valueStr));
// 存储数据
await dbi.put(txn, key, value);
// 提交事务
await txn.commit();
// 开启一个只读事务
final readTxn = await env.beginTxn();
// 检索数据
Uint8List retrievedValue = await dbi.get(readTxn, key);
String retrievedValueStr = utf8.decode(retrievedValue);
// 打印检索到的数据
print('Retrieved value for key "$keyStr": $retrievedValueStr');
// 关闭只读事务
await readTxn.abort();
// 关闭数据库环境
await env.close();
}
代码解释:
- 设置数据库环境路径:指定一个路径来存储LMDB数据库文件。
- 打开数据库环境:使用
MdbEnv.create
方法创建并打开一个数据库环境。 - 设置环境参数:通过
setMaxReaders
和setMapSize
方法设置环境参数。 - 开启事务:使用
env.beginTxn(write: true)
开启一个读写事务。 - 打开数据库:在事务中,使用
txn.openDbi
方法打开或创建一个数据库。 - 存储数据:将要存储的键值对编码为
Uint8List
,然后使用dbi.put
方法存储数据。 - 提交事务:使用
txn.commit
方法提交事务。 - 开启只读事务:使用
env.beginTxn()
开启一个只读事务。 - 检索数据:使用
dbi.get
方法根据键检索数据,并将结果解码为字符串。 - 关闭事务和环境:最后,关闭事务和数据库环境以释放资源。
这段代码展示了如何使用dart_lmdb2
进行基本的数据库操作。根据实际需求,你可以扩展这个示例,添加更多的功能和错误处理逻辑。