Flutter嵌入式数据库插件unqlite_flutter的使用

Flutter嵌入式数据库插件unqlite_flutter的使用

UnQLite 数据库插件为 Flutter 而封装。UnQLite 是一个嵌入式的 NoSQL 数据库,详情请见 此处

注意:目前仅支持键值存储。

待办事项:

  • ✅ 键值存储
  • ✅ JSON 文档存储

使用方法

键值存储

添加依赖项:

dependencies:
  unqlite: latest
  unqlite_flutter: latest

简单的键值存储示例:

import 'dart:io' show Platform;
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:unqlite/unqlite.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Future<void> testUnqlite() async {
    var appDocDir = await getApplicationDocumentsDirectory();
    final start = DateTime.now().millisecondsSinceEpoch;

    // 创建或打开数据库
    UnQLite db = UnQLite.open("${appDocDir.path}/test.db");

    // 保存键值对
    db.store("name", "Alex");
    db.store("age", 18);
    db.store(19, "haha");

    // 通过键获取值
    // 注意:你必须指定值的泛型类型
    debugPrint(db.fetch<String>("name"));
    debugPrint('${db.fetch<int>("age")}');
    debugPrint(db.fetch<String>(19));

    // 另一种获取值的方式
    db.fetchCallback<int>("age", (val) {
      debugPrint('age=$val');
    });

    // 另一种获取数据的方式,可能比 fetch 更快:
    var cursor = db.cursor();
    cursor.seek('name');
    debugPrint('=> ${cursor.key} => ${cursor.value}');

    // 使用事务,这是一个很棒的功能:
    var trans = db.transaction().begin();
    try {
      for (var i = 0; i < 100000; i++) {
        if (i == 10) {
          // 这里生成一个异常
          throw Exception('test');
        }
        db.store("transaction_$i", "here is a transaction_$i");
      }
      trans.commit();
    } catch (e) {
      // 事务在此处回滚
      trans.rollback();
    }

    // 使用迭代器遍历所有数据
    for (var entry in db.cursor()) {
      var content = '${entry.key} => ${entry.value}';
      debugPrint(content);
    }

    db.close();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('UnQLite app'),
        ),
        body: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              ElevatedButton(
                onPressed: () {
                  testUnqlite();
                },
                child: Text('测试UnQLite'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

JSON 存储

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:unqlite/unqlite.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Future<void> testJSON() async {
    var appDocDir = await getApplicationDocumentsDirectory();
    final start = DateTime.now().millisecondsSinceEpoch;

    UnQLite db = UnQLite.open("${appDocDir.path}/test2.db");
    var users = db.collection("users");
    users.create();

    // 保存 JSON 数据
    users.store(jsonDecode('''
{
        "title": "test json string",
        "author": [
                "arcticfox1919"
        ],
        "year": 2022,
        "like": "flutter"
}
    '''));
    users.store({'name': 'Mickey', 'age': 17});
    users.store([
      {'name': 'Alice', 'age': 18},
      {'name': 'Bruce', 'age': 19},
      {'name': 'Charlie', 'age': 20},
    ]);

    // 获取所有数据
    print(users.all());
    // print(users.fetch(0));
    // print(users.fetch(1));
    // print(users.fetch(2));
    // print(users.errorLog());

    print(users.creationDate());
    print(users.len());
    print(users.fetchCurrent());

    // 删除所有数据
    users.drop();
    db.close();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('UnQLite app'),
        ),
        body: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              ElevatedButton(
                onPressed: () {
                  testJSON();
                },
                child: Text('测试JSON存储'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

为什么使用它?

  • 比 Hive 更快,并且占用更少的内存。
  • 支持 JSON 文档。

缺点:由于使用了 Dart FFI,因此无法在 Web 上使用。

以下是性能测试数据(未列出内存百分比,但可以肯定的是 UnQLite 占用的内存更少):

UnQLite 性能数据:

UnQLite init:1 ms
write 100,000 entries :611 ms
fetch 100,000 entries :370 ms
seek  100,000 entries :215 ms
iterate 100,000 entries :225 ms
transaction rollback :39 ms

Hive 性能数据:

Hive init:48 ms
put 100,000 entries :807 ms
get 100,000 entries :290 ms

下面是用于性能测试的代码,均在相同的手机上以 profile 模式运行:

testUnQLite() async {
  var appDocDir = await getApplicationDocumentsDirectory();
  final start = DateTime.now().millisecondsSinceEpoch;
  UnQLite db = UnQLite.open("${appDocDir.path}/test.db");
  final t1 = DateTime.now().millisecondsSinceEpoch;

  for (var i = 0; i < 100000; i++) {
    db.store("my_key_$i", "Here is a value for testing—$i");
  }

  final t2 = DateTime.now().millisecondsSinceEpoch;
  for (var i = 0; i < 100000; i++) {
    var r = db.fetch<String>("my_key_$i");
    // debugPrint("fetch :$r");
  }
  final t3 = DateTime.now().millisecondsSinceEpoch;

  var cursor = db.cursor();
  for (var i = 0; i < 100000; i++) {
    cursor.seek('my_key_$i');
    // debugPrint('=> ${cursor.key} => ${cursor.value}');
  }
  final t4 = DateTime.now().millisecondsSinceEpoch;

  var count = 0;
  for (var entry in db.cursor()) {
    count++;
    var content = '${entry.key} => ${entry.value}';
    // debugPrint(content);
  }
  print('count => $count');
  final t5 = DateTime.now().millisecondsSinceEpoch;

  var trans = db.transaction().begin();
  try {
    for (var i = 0; i < 100000; i++) {
      if (i == 10) {
        throw Exception('test');
      }
      db.store("transaction_$i", "here is a transaction_$i");
    }
    trans.commit();
  } catch (e) {
    trans.rollback();
  }
  final t6 = DateTime.now().millisecondsSinceEpoch;

  debugPrint("UnQLite init:${t1 - start} ms");
  debugPrint("write 100,000 entries :${t2 - t1} ms");
  debugPrint("fetch 100,000 entries :${t3 - t2} ms");
  debugPrint("seek  100,000 entries :${t4 - t3} ms");
  debugPrint("iterate 100,000 entries :${t5 - t4} ms");
  debugPrint("transaction rollback :${t6 - t5} ms");
  db.close();
}

testHive() async {
  var appDocDir = await getApplicationDocumentsDirectory();
  var path = appDocDir.path;
  final start = DateTime.now().millisecondsSinceEpoch;
  Hive.init(path);
  var box = await Hive.openBox('testBox');

  final t1 = DateTime.now().millisecondsSinceEpoch;

  for (var i = 0; i < 100000; i++) {
    box.put("my_key_$i", "here is a transaction_$i");
  }

  final t2 = DateTime.now().millisecondsSinceEpoch;

  for (var i = 0; i < 100000; i++) {
    var name = box.get('my_key_$i');
  }

  final t3 = DateTime.now().millisecondsSinceEpoch;

  box.close();
  debugPrint("Hive init:${t1 - start} ms");
  debugPrint("put 100,000 entries :${t2 - t1} ms");
  debugPrint("get 100,000 entries :${t3 - t2} ms");
}

更多关于Flutter嵌入式数据库插件unqlite_flutter的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter嵌入式数据库插件unqlite_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


unqlite_flutter 是一个 Flutter 插件,允许你在 Flutter 应用中使用 UnQLite 嵌入式数据库。UnQLite 是一个轻量级的 NoSQL 数据库引擎,支持键值存储和文档存储(JSON 格式)。

以下是如何在 Flutter 项目中使用 unqlite_flutter 插件的步骤:

1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加 unqlite_flutter 依赖:

dependencies:
  flutter:
    sdk: flutter
  unqlite_flutter: ^0.1.0  # 请检查最新版本

然后运行 flutter pub get 来获取依赖。

2. 导入包

在你的 Dart 文件中导入 unqlite_flutter 包:

import 'package:unqlite_flutter/unqlite_flutter.dart';

3. 初始化数据库

在你的应用中使用 UnQLite 类来初始化数据库。通常,你可以在 main 函数或某个初始化方法中进行初始化。

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // 初始化 UnQLite 数据库
  UnQLite unqlite = UnQLite();
  await unqlite.open('my_database.db');
  
  runApp(MyApp());
}

4. 数据库操作

你可以使用 UnQLite 类提供的方法进行数据库操作,例如插入、查询、更新和删除数据。

插入数据

await unqlite.insert('key1', 'value1');

查询数据

String? value = await unqlite.get('key1');
print(value);  // 输出: value1

更新数据

await unqlite.update('key1', 'new_value1');

删除数据

await unqlite.delete('key1');

关闭数据库

在应用关闭或不再需要数据库时,记得关闭数据库:

await unqlite.close();

5. 处理 JSON 数据

UnQLite 支持存储 JSON 格式的数据。你可以使用 jsonEncodejsonDecode 来处理 JSON 数据。

import 'dart:convert';

// 插入 JSON 数据
Map<String, dynamic> data = {'name': 'John', 'age': 30};
await unqlite.insert('user1', jsonEncode(data));

// 查询 JSON 数据
String? jsonString = await unqlite.get('user1');
if (jsonString != null) {
  Map<String, dynamic> user = jsonDecode(jsonString);
  print(user['name']);  // 输出: John
}

6. 错误处理

在使用 unqlite_flutter 时,建议对可能出现的异常进行处理。

try {
  await unqlite.insert('key1', 'value1');
} catch (e) {
  print('Error: $e');
}

7. 使用 Provider 或 Riverpod 进行状态管理

如果你在你的 Flutter 应用中使用状态管理工具(如 Provider 或 Riverpod),你可以将 UnQLite 实例封装在状态管理类中,以便在整个应用中访问数据库。

8. 示例代码

以下是一个简单的示例,展示了如何在 Flutter 应用中使用 unqlite_flutter 插件:

import 'package:flutter/material.dart';
import 'package:unqlite_flutter/unqlite_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  UnQLite unqlite = UnQLite();
  await unqlite.open('my_database.db');
  
  runApp(MyApp(unqlite: unqlite));
}

class MyApp extends StatelessWidget {
  final UnQLite unqlite;

  MyApp({required this.unqlite});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('UnQLite Demo')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () async {
                  await unqlite.insert('key1', 'value1');
                  print('Data inserted');
                },
                child: Text('Insert Data'),
              ),
              ElevatedButton(
                onPressed: () async {
                  String? value = await unqlite.get('key1');
                  print('Fetched Data: $value');
                },
                child: Text('Fetch Data'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
回到顶部