持续创作,加速成长!这是我参与「掘金日新计划 · 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 线程的压力。