[官文翻译]Futter超快数据库Isar - 技巧 - 数据迁移

441 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情


Isar:用于 Futter 可跨平台的超快数据库

官方文档:Home | Isar Database

pub:isar | Dart Package (flutter-io.cn)

本文翻译自:
Data migration | Isar Database

译时版本:3.0.2


数据迁移

如果添加或移除了集合、字段或索引,Isar 会自动迁移数据库 Schema 。 有时候你可能也想要迁移数据。 Isar 没有内置解决方案,因为这样会强加主观上的迁移限制。 要实现符合要求的迁移逻辑也很容易。

在该示例中我们想为整个数据库使用单个版本。 我们使用 shared preferences 存储现在的版本,然后将它和要迁移的版本进行比较。 如果版本不匹配,我们迁移数据然后更新版本。

也可能为每个集合使用它自己的版本,然后分别进行迁移。

想象一下,我们有一个 user 集合,带有 birthday (出生日)字段。 在应用的版本 2 中,我们需要添加额外的 birth year (出生年)字段 用来基于年龄查询用户。

版本 1:

@collection
class User {
  Id? id;

  late String name;

  late DateTime birthday;
}

版本 2:

@collection
class User {
  Id? id;

  late String name;

  late DateTime birthday;

  short get birthYear => birthday.year;
}

问题是现有的 user 模型会有一个空的 birthYear 字段因为它在版本 1 中没有。 我们需要将迁移数据,设置 birthYear 字段。

import 'package:isar/isar.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() async {
  final isar = await Isar.open([UserSchema]);

  await performMigrationIfNeeded(isar);

  runApp(MyApp(isar: isar));
}

Future<void> performMigrationIfNeeded(Isar isar) async {
  final prefs = await SharedPreferences.getInstance();
  final currentVersion = prefs.getInt('version') ?? 2;
  switch(currentVersion) {
    case 1:
      await migrateV1ToV2(isar);
      break;
    case 2:
      // 如果版本没有设置(新安装时)或者已经是 2 , 不需要迁移。
      return;
    default:
      throw Exception('Unknown version: $currentVersion');
  }

  // 更新版本
  await prefs.setInt('version', 2);
}

Future<void> migrateV1ToV2(Isar isar) async {
  final userCount = await isar.users.count();

  // 对 user 数据进行分页以避免一次把所有的 user 都加载到内存中
  for (var i = 0; i < userCount; i += 50) {
    final users = await isar.users.where().offset(i).limit(50).findAll();
    await isar.writeTxn((isar) async {
      // 不需要进行任何更新因为 birthYear getter 正在使用
      await isar.users.putAll(users);
    });
  }
}

如果你需要迁移大量的数据,考虑使用后台隔离(isolate)以避免 UI 线程的压力。