ObjectBox to wysokowydajna baza danych NoSQL zoptymalizowana dla urządzeń mobilnych i brzegowych. W przeciwieństwie do SQLite, używa własnego formatu przechowywania opartego na płaskich plikach bez warstwy SQL. Według ObjectBox Benchmarks, 2024, ObjectBox wykonuje operacje wstawiania i odczytu 10–100 razy szybciej niż SQLite na urządzeniach Android, co czyni go najlepszym wyborem dla wymagających aplikacji mobilnych.
Najważniejsze
ObjectBox — to in-memory baza danych NoSQL opracowana przez niemiecką firmę ObjectBox.io. W przeciwieństwie do tradycyjnych relacyjnych baz danych, ObjectBox przechowuje obiekty bezpośrednio w płaskich plikach, używając własnego formatu SLOT (Super Lightweight Object Tree). Eliminuje to narzut związany z ORM i parserem SQL. Format SLOT jest zoptymalizowany do pracy na urządzeniach z ograniczoną pamięcią: dane są defragmentowane automatycznie, a rozmiar bazy danych jest średnio 4–6 razy mniejszy niż w przypadku równoważnej bazy SQLite przy tej samej liczbie rekordów.
ObjectBox obsługuje wszystkie główne platformy mobilne: Android, iOS i Flutter. Dla Androida dostępne jest generowanie kodu przez ObjectBox Gradle Plugin, który przetwarza adnotowane encje i tworzy klasy Box do pracy z danymi. Dla Flutter używana jest natywna wtyczka z opakowaniem Dart. Oprócz platform mobilnych, ObjectBox działa na Linux, macOS, Windows i WebAssembly, co pozwala na ponowne wykorzystanie modelu danych między aplikacją mobilną a synchronizacją serwerową.
Według danych badania ObjectBox (2023), baza danych jest używana w ponad 5000 aplikacjach w Google Play, w tym w aplikacjach z publicznością przekraczającą 10 milionów użytkowników. Główne scenariusze: buforowanie danych, praca w trybie offline i przechowywanie szeregów czasowych (IoT). ObjectBox jest szczególnie popularny w aplikacjach do śledzenia zdrowia i fitnessu, gdzie wymagane jest szybkie zapisywanie odczytów czujników na urządzeniu bez stałego połączenia internetowego oraz do zbierania analityki z wielu urządzeń.
ObjectBox pojawił się jako alternatywa dla Realm i SQLite na platformę Android. Pierwsza stabilna wersja została wydana w 2018 roku. Kluczowa różnica w stosunku do Realm — ObjectBox nie ma ograniczeń GPL (używa Apache 2.0) i obsługuje więcej platform: od urządzeń mobilnych po serwery na Linux.
ObjectBox zapewnia: automatyczne generowanie klas Box, wbudowane indeksy do szybkiego wyszukiwania, transakcje z obsługą wycofywania, reaktywne zapytania przez RxJava i Kotlin Flow, a także synchronizację między urządzeniami przez ObjectBox Sync (autorski protokół). W przeciwieństwie do Firebase Realtime Database, ObjectBox Sync działa w modelu peer-to-peer bez centralnego serwera, co zmniejsza opóźnienia i koszty infrastruktury.
ObjectBox przechowuje dane we własnym binarnym formacie .mdb (ObjectBox Data File). Każda encja (Entity) jest mapowana na jeden plik, gdzie rekordy są przechowywane sekwencyjnie ze stałym przesunięciem. Pozwala to odczytywać i zapisywać poszczególne obiekty bez pełnego skanowania pliku.
Do pracy z ObjectBox nie jest potrzebny SQL: zapytania są budowane przez fluent-API w kodzie. Kompilator generuje pomocnicze klasy MyObjectBox i pudełka (Box), które hermetyzują wszystkie operacje CRUD. Model danych jest opisywany przez adnotacje @Entity, @Id, @Index i @Relation.
// Podłączenie ObjectBox w Android
class App: Application() {
lateinit var boxStore: BoxStore
override fun onCreate() {
super.onCreate()
boxStore = MyObjectBox.builder()
.androidContext(this)
.build()
}
}
Według oficjalnych benchmarków, ObjectBox znacznie przewyższa SQLite pod względem szybkości operacji, szczególnie przy wsadowym wstawianiu i masowym odczycie. SQLite pozostaje jednak standardem de facto dla aplikacji mobilnych ze względu na rozpowszechnienie i wbudowane wsparcie SQL.
| Operacja | ObjectBox | SQLite | Różnica |
|---|---|---|---|
| Wstawianie (1000 rekordów) | ~5 ms | ~180 ms | x36 szybciej |
| Odczyt (1000 rekordów) | ~3 ms | ~70 ms | x23 szybciej |
| Aktualizacja (1000 rekordów) | ~6 ms | ~150 ms | x25 szybciej |
| Wyszukiwanie po indeksie | ~0.1 ms | ~2 ms | x20 szybciej |
| Rozmiar BD (1000 obiektów) | ~28 KB | ~112 KB | 4 razy mniejszy |
ObjectBox przegrywa z SQLite w scenariuszach, gdzie potrzebne są złożone zapytania JOIN, funkcje agregujące (SUM, COUNT z grupowaniem) lub integracja z istniejącym schematem SQL. Jeśli projekt już używa SQLite z Room ORM — migracja na ObjectBox będzie wymagać przepisania całej logiki dostępu do danych. ObjectBox nie obsługuje również niestandardowych zapytań SQL — tylko fluent-API. Jednak dla typowych operacji CRUD i buforowania ObjectBox daje wzrost wydajności do 100 razy, co potwierdzają oficjalne benchmarki na urządzeniach Android z różnymi wersjami OS.
ObjectBox używa adnotacji do definiowania encji. Po kompilacji tworzone są klasy Box z metodami put, get, remove i query. Poniżej przedstawiono typowe operacje dla modelu Task w aplikacji do listy zadań.
Każda encja jest adnotowana @Entity. Pole z @Id staje się kluczem głównym, @Index przyspiesza wyszukiwanie po polu. ObjectBox obsługuje automatyczne generowanie ID przy wartości 0.
@Entity
data class Task(
@Id var id: Long = 0,
@Index var title: String = "",
var isCompleted: Boolean = false,
var priority: Int = 0
)
Box — główna klasa do pracy z encjami. Metoda put() zapisuje lub aktualizuje obiekt, get() odczytuje po ID, remove() usuwa. Wszystkie podstawowe operacje są synchroniczne i wykonywane na wątku wywołującym.
val taskBox: Box<Task> = boxStore.boxFor(Task::class.java)
// Tworzenie
val task = Task(title = "Kup produkty", priority = 3)
val newId = taskBox.put(task)
// Odczyt
val savedTask = taskBox.get(newId)
// Aktualizacja
savedTask.isCompleted = true
taskBox.put(savedTask)
// Usuwanie
taskBox.remove(newId)
ObjectBox obsługuje zapytania reaktywne przez .subscribe(). Subskrybent otrzymuje powiadomienia przy każdej zmianie danych odpowiadającej warunkom zapytania. Jest to wygodne dla UI, które automatycznie aktualizuje listę przy dodawaniu lub usuwaniu elementów.
val query = taskBox.query()
.equal(Task_.isCompleted, false)
.orderDesc(Task_.priority)
.build()
query.subscribe { tasks ->
// tasks — List, aktualizowana automatycznie
updateUi(tasks)
}
ObjectBox obsługuje relacje między encjami — To-One, To-Many i Many-to-Many. Relacje są definiowane przez adnotację @Relation. W przeciwieństwie do SQLite, ObjectBox nie używa kluczy obcych: relacje są realizowane przez listy ID w płaskich plikach, co przyspiesza nawigację po grafie obiektów.
Relacja @Backlink pozwala przejść od encji potomnej do nadrzędnej bez osobnego pola referencji. ObjectBox automatycznie utrzymuje odwrotne odwołanie, co eliminuje duplikację danych i synchronizację między dwiema tabelami.
ObjectBox Query Builder pozwala budować łańcuchy warunków: equal, notEqual, greater, less, in, contains, startsWith. Wszystkie warunki są łączone przez and/or. Wynik można sortować, ograniczać i uzyskać jako List lub LazyList (dla dużych zbiorów danych).
ObjectBox automatycznie indeksuje pole @Id. Dla niestandardowych indeksów używaj adnotacji @Index na polach, po których często wykonywane są zapytania. Indeksy przyspieszają zapytania equal i in, ale spowalniają wstawianie — nie indeksuj pól, po których wyszukiwanie nie jest wykonywane. ObjectBox obsługuje indeksy złożone do filtrowania po kilku polach jednocześnie. Indeksy złożone są szczególnie przydatne do filtrów na listach: na przykład wyszukiwanie niezakończonych zadań o wysokim priorytecie jest dziesiątki razy szybsze z indeksem złożonym na polach isCompleted i priority.
ObjectBox Sync — autorska technologia do synchronizacji danych między urządzeniami w czasie rzeczywistym. Używa protokołu opartego na WebSocket z rozwiązywaniem konfliktów według last-writer-wins. Sync nadaje się do aplikacji, które potrzebują synchronizacji offline: notatki, listy zadań, dane IoT z wielu czujników. Jednak dla produkcji wymagany jest zakup licencji.
// Zapytanie z wieloma warunkami
val highPriorityIncomplete = taskBox.query()
.greater(Task_.priority, 5)
.equal(Task_.isCompleted, false)
.build()
.find()
// Wyszukiwanie po podłańcuchu
val searchResults = taskBox.query()
.contains(Task_.title, "produkt", StringOrder.CASE_INSENSITIVE)
.build()
.find()
Często zadawane pytania
ObjectBox jest rozpowszechniany na licencji Apache 2.0, która pozwala na komercyjne użycie bez ograniczeń. Funkcja ObjectBox Sync (synchronizacja międzyplatformowa) jest własnościowa i wymaga zakupu licencji dla produkcji.
BoxStore jest bezpieczny wątkowo: wiele wątków może jednocześnie odczytywać dane. Zapis jest blokowany na poziomie Box. Dla złożonych transakcji używaj boxStore.runInTx(), który gwarantuje atomowość grupy operacji.
Tak, ObjectBox obsługuje Kotlin Multiplatform (KMP) od wersji 3.0. Dostępne są targety Android, iOS, JVM i Native. Dla KMP używany jest osobny plugin Gradle objectbox-kotlin z obsługą expect/actual.
ObjectBox przechowuje dane w plikach .mdb w katalogu aplikacji. Aby wykonać kopię zapasową, skopiuj cały katalog ObjectBox przez BoxStore.copy() lub ręcznie skopiuj pliki po wywołaniu boxStore.close(). Żywych plików nie można kopiować — uszkodzi to dane.
Room — ORM na bazie SQLite, wymaga zapytań SQL i ma narzut na mapowanie obiektów. ObjectBox to NoSQL bez SQL, jest o rząd szybszy, ale nie obsługuje złożonych JOIN i nie jest relacyjną bazą danych. Wybór zależy od zadania: dla danych relacyjnych — Room, dla szybkiego przechowywania obiektów — ObjectBox.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również