ObjectBox Dart/Flutter мультиизолированный доступ
Создание отдельной ветки для вопроса, указанного в комментарии ...
Как ObjectBox обрабатывает одновременные (разными потоками / изоляторами) запросы записи? Пример моего варианта использования: вызов FCM «onBackgroundmessage» выполняется в другом изолированном пространстве, в то же время может произойти несколько запросов на запись. «Улей» в этом случае полностью рушится. Есть ли встроенное решение в ObjectBox?
2 ответа
ObjectBox для dart основан на собственной базовой библиотеке ObjectBox, которая обрабатывает параллелизм с помощью транзакций . Позвольте мне выделить несколько моментов, имеющих отношение к вопросу:
- Транзакции управляют многопоточностью; например, транзакция привязана к потоку и наоборот.
- Транзакции (только для чтения) никогда не блокируются и не блокируют транзакцию записи.
- Одновременно может быть только одна транзакция записи; они выполняются строго один за другим (последовательно).
Что касается изолят в Dart / флаттере - да, они могут безопасно получить доступ к такому же магазину, вам просто нужно , чтобы убедиться , что он действительно является тот же родным экземпляром магазина. Для этого вы делаете следующие шаги:
- Создать
Store()
instance в вашем основном изоляте, как обычно. - Получать
ByteData store.reference
который содержит информацию о собственном магазине. - Отправьте ссылку на другой изолят через
SendPort
. - В другом изоляте получите ссылку и откройте локальный экземпляр, используя
Store.fromReference(getObjectBoxModel(), msg as ByteData)
. - Теперь у обоих изолятов есть собственный дротик.
Store
экземпляры, которые внутренне используют одно и то же базовое собственное хранилище. Следовательно, их транзакции синхронизированы, они оба видят одни и те же данные и получают уведомления об изменении данных. 🎉
Вы можете увидеть код, который я только что описал для этого тестового примера: https://github.com/objectbox/objectbox-dart/blob/461a948439dcc42f3956b7d21b232eb9c2bc26e1/objectbox/test/isolates_test.dart#L50
Убедитесь, что вы не закрываете магазин, пока его использует другой изолят. Лучше вообще не закрывать его - это лучший способ для обычных приложений без огромной фоновой работы.
Спустя несколько лет после принятого ответа у objectbox теперь есть дополнительная функция, которая может хорошо работать с изолятом.
Это функция Store.attach() . Используя эту функцию, вы можете подключить хранилище, указав путь к базе данных, не беспокоясь о том, что отдельный изолят закроет хранилище:
Фактическое базовое хранилище закрывается только тогда, когда закрывается последний экземпляр хранилища (например, при выходе из приложения).
В моем случае мне пришлось использоватьpackage для выполнения фоновой задачи, которая зависит от хранилища объектов.
Вы можете создать класс «инициализатор» следующим образом:
class ObjectBox {
static late final Store store;
static Future initialize() async {
var docsDir = await getApplicationDocumentsDirectory();
var dbPath = p.join(docsDir.path, "objectbox");
if (Store.isOpen(dbPath)) {
store = Store.attach(getObjectBoxModel(), dbPath);
} else {
store = await openStore(directory: dbPath);
}
}
}
Получив это, вы можете использоватьinitialize()
в вашем изоляте. Пример сworkmanager
упаковка:
main.dart
@pragma("vm:entry-point")
void callbackDispatcher() {
Workmanager().executeTask((taskName, inputData) async {
await ObjectBox.initialize(); // Initialize in background isolate.
return true;
});
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await ObjectBox.initialize(); // Initialize in main isolate
Workmanager().initialize(callbackDispatcher);
runApp(const MyApp());
}
Таким образом, даже если вы закроете базу данных в основном изоляте, фоновый изолят продолжит функционировать. Само базовое хранилище закрывается после закрытия всех экземпляров хранилища.