Realm ist die beste Android-Datenbanklösung
Veröffentlicht: 2022-03-11Seit der Erfindung von Android verwenden wir App-Entwickler SQLite, um unsere lokalen Daten zu speichern. Manchmal direkt mit SQL-Anweisungen, manchmal mit einem Object-Relational Mapper (ORM) als Abstraktionsschicht, aber so oder so, wir haben am Ende des Tages SQLite verwendet.
Trotz aller Vorteile von SQLite wünschten wir uns jedoch manchmal Alternativen zu einem relationalen Modell: Etwas, das uns das Hinzufügen von Boilerplate-Code zum Konvertieren von Werten in und aus der Datenbank erspart oder es uns ermöglicht, das Einrichten von Mappings zu überspringen zwischen Klassen und Tabellen, Feldern und Spalten, Fremdschlüsseln usw.
Mit anderen Worten, eine Datenbank mit Datenstrukturen, die denen ähnlicher sind, die wir tatsächlich auf Anwendungsebene verwenden. Besser noch, wenn es vom Design her speichereffizient sein könnte, was eine bessere Erfahrung in ressourcenbeschränkten Geräten ermöglicht, wäre das großartig.
Dies sind in der Tat einige der sofort einsatzbereiten Vorteile, die wir mit Realm erhalten, einer Datenbankplattform mit einer eigenen Architektur, die sich als neue Alternative zu SQLite herausgestellt hat.
Dieser Artikel stellt einige der Hauptgründe vor, warum Realm so viel Aufmerksamkeit erregt hat und warum Sie es vielleicht ausprobieren möchten. Es erläutert einige der wichtigsten Vorteile, die Realm Android-Entwicklern gegenüber SQLite bietet.
Da Realm auf mehreren Plattformen verfügbar ist, sind einige der in diesem Artikel behandelten Themen auch für andere mobile Plattformen wie iOS, Xamarin und React Native relevant.
SQLite: Es funktioniert, aber es ist nicht das, was Sie die meiste Zeit brauchen
Die meisten Mobilentwickler sind wahrscheinlich mit SQLite vertraut. Es gibt es seit dem Jahr 2000 und es ist wohl die am häufigsten verwendete relationale Datenbank-Engine der Welt.
SQLite hat eine Reihe von Vorteilen, die wir alle anerkennen, einer davon ist die native Unterstützung auf Android.
Die Tatsache, dass es sich um eine relationale Standard-SQL-Datenbank handelt, minimiert auch die Lernkurve für diejenigen, die einen relationalen Datenbankhintergrund haben. Es bietet auch eine recht gute Leistung, wenn es sein volles Potenzial ausschöpft (Nutzung von Funktionen wie vorbereiteten Kontoauszügen, Massenoperationen mit Transaktionen usw.). Obwohl SQLite möglicherweise nicht sehr gut für alle Ihre Anforderungen skaliert.
Der direkte Umgang mit SQL-Anweisungen hat jedoch eine Reihe von Nachteilen.
Gemäß der offiziellen Android-Dokumentation sind die folgenden Schritte erforderlich, um mit dem Lesen/Schreiben in SQLite zu beginnen:
- Beschreiben Sie Ihr Schema anhand von Vertragsklassen.
- Definieren Sie Ihre Befehle zum Erstellen/Löschen von Tabellen in Zeichenfolgen.
- Erweitern
SQLiteOpenHelper
, um Erstellungsbefehle auszuführen und Upgrades/Downgrades zu verwalten.
Sobald Sie dies getan haben, können Sie Ihre Datenbank lesen und schreiben. Sie müssen jedoch zwischen den Objekten in Ihrer Anwendung und den Werten in der Datenbank hin und her konvertieren. Lange Rede kurzer Sinn: Es ist eine Menge Boilerplate-Code!
Ein weiteres Problem ist die Wartbarkeit. Wenn Ihr Projekt größer wird und die Notwendigkeit entsteht, komplexere Abfragen zu schreiben, werden Sie am Ende große Teile von rohen SQL-Abfragen in Zeichenfolgen haben. Wenn Sie später die Logik dieser Abfragen ändern müssen, kann dies ziemlich umständlich sein.
Trotz seiner Nachteile gibt es Fälle, in denen die Verwendung von Raw-SQL die beste Option ist. Ein Beispiel ist, wenn Sie eine Bibliothek entwickeln, bei der Leistung und Größe kritische Faktoren sind und das Hinzufügen einer Bibliothek eines Drittanbieters nach Möglichkeit vermieden werden sollte.
Objektrelationaler Mapper: Das Pflaster für SQL-Herausforderungen
Um uns den Umgang mit rohem SQL zu ersparen, kamen ORMs zu Hilfe.
Einige der bekanntesten Android-ORMs sind DBFlow, greenDAO und OrmLite.
Der größte Wert, den sie bringen, ist die SQLite-Abstraktion, mit der wir Datenbankentitäten relativ einfach Java-Objekten zuordnen können.
Neben anderen Vorteilen können Anwendungsentwickler mit Objekten arbeiten, einer viel vertrauteren Datenstruktur. Es hilft auch bei der Wartbarkeit, da wir High-Level-Objekte jetzt mit einer stärkeren Typisierung handhaben und die Drecksarbeit den Bibliotheken überlassen. Weniger Probleme beim Erstellen von Abfragen durch Verketten von Zeichenfolgen oder manuelles Herstellen der Verbindung mit der Datenbank. Weniger Tippfehler.
Obwohl es eine Tatsache ist, dass diese ORMs die Messlatte für Android-Datenbanken höher gelegt haben, haben sie auch ihre Nachteile. In vielen Fällen laden Sie am Ende unnötige Daten.
Hier ist ein Beispiel.
Angenommen, Sie haben eine Tabelle mit 15 Spalten, und in einem bestimmten Bildschirm Ihrer App wird eine Liste von Objekten aus dieser Tabelle angezeigt. Diese Liste zeigt Werte aus nur drei Spalten an. Wenn Sie also alle Daten aus der Tabellenzeile laden, bringen Sie am Ende fünfmal mehr Daten, als Sie tatsächlich für diesen Bildschirm benötigt haben.
Um ehrlich zu sein, in einigen dieser Bibliotheken können Sie im Voraus angeben, welche Spalten Sie abrufen möchten, aber dafür müssen Sie weiteren Code hinzufügen, und selbst dann wird das nicht ausreichen, falls Sie nur genau wissen können, welche Spalten Sie möchten verwenden, nachdem Sie sich die Daten selbst angesehen haben: Einige Daten könnten sowieso unnötig geladen werden.
Darüber hinaus gibt es häufig Szenarien, in denen Sie komplexe Abfragen durchführen müssen, und Ihre ORM-Bibliothek bietet Ihnen einfach keine Möglichkeit, diese Abfragen mit ihrer API zu beschreiben. Das kann zum Beispiel dazu führen, dass Sie ineffiziente Abfragen schreiben, die mehr Berechnungen durchführen, als Sie benötigen.
Die Folge ist ein Leistungsverlust, der dazu führt, dass Sie auf Raw-SQL zurückgreifen. Obwohl dies für viele von uns kein Deal Breaker ist, verletzt es den Hauptzweck des objektrelationalen Mappings und führt uns zurück zu einigen der oben genannten Probleme in Bezug auf SQLite.
Realm: Eine perfekte Alternative
Realm Mobile Database ist eine Datenbank, die von Grund auf für mobile Geräte entwickelt wurde.
Der Hauptunterschied zwischen Realm und ORMs besteht darin, dass Realm keine Abstraktion ist, die auf SQLite aufbaut, sondern eine völlig neue Datenbank-Engine. Anstelle eines relationalen Modells basiert es auf einem Objektspeicher. Sein Kern besteht aus einer in sich geschlossenen C++-Bibliothek. Es unterstützt derzeit Android, iOS (Objective-C und Swift), Xamarin und React Native.
Realm wurde im Juni 2014 gestartet, ist also derzeit zweieinhalb Jahre alt (ziemlich neu!).
Während Serverdatenbanktechnologien seit 2007 eine Revolution durchmachten und viele neue auftauchten, blieb die Datenbanktechnologie für mobile Geräte bei SQLite und seinen Wrappern hängen. Dies war eine der Hauptmotivationen, etwas von Grund auf neu zu schaffen. Darüber hinaus erforderten, wie wir sehen werden, einige der Funktionen von Realm grundlegende Änderungen an der Art und Weise, wie sich eine Datenbank auf niedriger Ebene verhält, und das war einfach nicht möglich, etwas auf SQLite aufzubauen.
Aber ist Realm es wirklich wert? Hier sind die wichtigsten Gründe, warum Sie erwägen sollten, Realm zu Ihrem Werkzeuggürtel hinzuzufügen.
Einfaches Modellieren
Hier ist ein Beispiel für einige Modelle, die mit Realm erstellt wurden:
public class Contact extends RealmObject { @PrimaryKey String id; protected String name; String email; @Ignore public int sessionId; //Relationships private Address address; private RealmList<Contact> friends; //getters & setter left out for brevity }
public class Address extends RealmObject { @PrimaryKey public Long id; public String name; public String address; public String city; public String state; public long phone; }
Ihre Modelle erweitern sich von RealmObject. Realm akzeptiert alle primitiven Typen und ihre Boxed-Typen (außer char
), String
, Date
und byte[]
. Es unterstützt auch Unterklassen von RealmObject
und RealmList<? extends RealmObject>
RealmList<? extends RealmObject>
um Beziehungen zu modellieren.
Felder können jede Zugriffsebene haben (privat, öffentlich, geschützt usw.). Alle Felder werden standardmäßig beibehalten, und Sie müssen nur „besondere“ Felder annotieren (z. B. @PrimaryKey
für Ihr Primärschlüsselfeld, @Ignore
, um nicht persistente Felder festzulegen usw.).
Das Interessante an diesem Ansatz ist, dass Klassen im Vergleich zu ORMs weniger „annotationsverschmutzt“ bleiben, da Sie in den meisten von ihnen Annotationen benötigen, um Klassen Tabellen, reguläre Felder Datenbankspalten, Fremdschlüsselfelder anderen Tabellen usw. zuzuordnen an.
Beziehungen
Wenn es um Beziehungen geht, gibt es zwei Möglichkeiten:
Fügen Sie ein Modell als Feld aus einem anderen Modell hinzu. In unserem Beispiel enthält die
Contact
einAddress
, das ihre Beziehung definiert. Ein Kontakt kann eine Adresse haben, aber nichts hindert diese Adresse daran, anderen Kontakten hinzugefügt zu werden. Das ermöglicht Eins-zu-eins- und Eins-zu-viele-Beziehungen.Fügen Sie eine
RealmList
der referenzierten Modelle hinzu.RealmLists
verhalten sich ganz wie gute alte Java-Lists
und fungieren als Container von Realm-Objekten. Wir können sehen, dass unserContact
eineRealmList
von Kontakten hat, die in diesem Beispiel ihre Freunde sind. Mit diesem Ansatz können Eins-zu-Viele- und Viele-zu-Viele-Beziehungen modelliert werden.
Ich mag diese Art, Beziehungen darzustellen, weil sie sich für uns Java-Entwickler sehr natürlich anfühlt. Indem wir diese Objekte (oder Listen dieser Objekte) direkt als Felder unserer Klasse hinzufügen, genau wie wir es für andere Nicht-Modellklassen tun würden, müssen wir uns nicht mit SQLite-Einstellungen für Fremdschlüssel befassen.
Achtung: Modellvererbung wird nicht unterstützt. Die aktuelle Problemumgehung besteht darin, Komposition zu verwenden. Wenn Sie also beispielsweise ein Animal
-Modell haben und hoffen, ein Dog
-Modell zu erstellen, das sich von Animal
erweitert, müssen Sie stattdessen eine Animal
-Instanz als Feld in Dog
hinzufügen. Es gibt eine große Debatte über Komposition vs. Vererbung. Wenn Sie Vererbung verwenden möchten, müssen Sie dies definitiv über Realm wissen. Mit SQLite könnte dies unter Verwendung von zwei Tabellen (eine für die Eltern und eine für die Kinder) implementiert werden, die durch einen Fremdschlüssel verbunden sind. Einige ORMs erlegen diese Einschränkung auch nicht auf, z. B. DBFlow.
Rufen Sie nur Daten ab, die Sie benötigen! Zero-Copy-Design
Dies ist ein Killer-Feature.
Realm wendet das Konzept des Zero-Copy-Designs an, was bedeutet, dass Daten niemals in den Speicher kopiert werden. Die Ergebnisse, die Sie aus einer Abfrage erhalten, sind eigentlich nur Zeiger auf die echten Daten. Die Daten selbst werden träge geladen, wenn Sie darauf zugreifen.
Sie haben beispielsweise ein Modell mit 10 Feldern (Spalten in SQL). Wenn Sie Objekte dieses Modells abfragen, um sie aufgelistet auf einem Bildschirm anzuzeigen, und Sie nur drei der 10 Felder benötigen, um die Listenelemente zu füllen, werden nur diese Felder abgerufen.
Infolgedessen sind Abfragen blitzschnell (siehe hier und hier für einige Benchmark-Ergebnisse).
Dies ist ein großer Vorteil gegenüber ORMs, die normalerweise alle Daten aus ausgewählten SQL-Zeilen im Voraus laden.
Das Laden des Bildschirms wird dadurch erheblich effizienter, ohne dass der Entwickler weitere Anstrengungen erfordert: Es ist nur das Standardverhalten von Realm.
Darüber hinaus bedeutet dies auch, dass Apps weniger Speicher verbrauchen, und wenn man bedenkt, dass wir über eine ressourcenbeschränkte Umgebung wie mobile Geräte sprechen, kann das einen großen Unterschied machen.
Eine weitere Folge des Zero-Copy-Ansatzes ist, dass von Realm verwaltete Objekte automatisch aktualisiert werden.
Daten werden niemals in den Speicher kopiert. Wenn Sie Ergebnisse von einer Abfrage haben und ein anderer Thread diese Daten nach Ihrer Abfrage in der Datenbank aktualisiert hat, spiegeln die Ergebnisse, die Sie besitzen, diese Änderungen bereits wider. Ihre Ergebnisse sind nur Hinweise auf die eigentlichen Daten. Wenn Sie also auf Werte aus Feldern zugreifen, werden die aktuellsten Daten zurückgegeben.
Wenn Sie beispielsweise bereits Daten aus Realm-Objekten gelesen und auf dem Bildschirm angezeigt haben und Updates erhalten möchten, wenn sich die zugrunde liegenden Daten ändern, können Sie einen Listener hinzufügen:
final RealmResults<Contact> johns = realm.where(Contact.class).beginsWith("name", "John ").findAll(); johns.addChangeListener(new RealmChangeListener<RealmResults<Contact>>() { @Override public void onChange(RealmResults<Contact> results) { // UPDATE UI } });
Es ist nicht nur ein Wrapper
Obwohl wir Dutzende von Optionen für ORMs haben, sind sie Wrapper, und alles hängt von SQLite darunter ab, was ihre Reichweite einschränkt. Im Gegensatz dazu ist Realm nicht nur ein weiterer SQLite-Wrapper. Es hat die Freiheit, Funktionen bereitzustellen, die ORMs einfach nicht bieten können.
Eine der grundlegenden Änderungen bei Realm ist die Möglichkeit, Daten als Objektgraphspeicher zu speichern.
Das bedeutet, dass Realm von der Ebene der Programmiersprache bis zur Datenbank vollständig aus Objekten besteht. Folglich wird beim Schreiben und Lesen von Werten im Vergleich zu einer relationalen Datenbank viel weniger Konvertierung hin und her durchgeführt.
Datenbankstrukturen spiegeln die von Anwendungsentwicklern verwendeten Datenstrukturen genauer wider. Tatsächlich ist dies einer der Hauptgründe, warum es bei der serverseitigen Entwicklung eine Bewegung weg von der relationalen Modellierung und hin zu aggregierten Modellen gibt. Endlich bringt Realm einige dieser Ideen in die mobile Entwicklungswelt.
Wenn wir an Komponenten in der Architektur von Realm denken, befindet sich ganz unten der Kern mit der grundlegendsten Implementierung der Plattform. Darüber hinaus werden wir Bindungsbibliotheken für jede unterstützte Plattform haben.
Wenn Sie einen Wrapper für eine Technologie verwenden, über die Sie keine Kontrolle haben, müssen Sie schließlich eine Art Abstraktionsschicht darum herum bereitstellen.
Reichsbindungsbibliotheken sind so dünn wie möglich gestaltet, um die Abstraktionskomplexität zu reduzieren. Sie propagieren meist die Designidee von Core. Durch die Kontrolle über die gesamte Architektur arbeiten diese Komponenten besser miteinander synchronisiert.
Ein praktisches Beispiel ist der Zugriff auf andere referenzierte Objekte (Fremdschlüssel in SQL). Die Dateistruktur von Realm basiert auf nativen Links. Wenn Sie also Beziehungen abfragen, anstatt eine ORM-Abstraktion in relationale Tabellen übersetzen und/oder mehrere Tabellen verknüpfen zu müssen, erhalten Sie rohe Links zu den Objekten auf Dateisystemebene im Dateiformat.
Das sind Objekte, die direkt auf andere Objekte zeigen. Das Abfragen einer Beziehung entspricht also beispielsweise dem Abfragen einer Integer-Spalte. Es sind keine teuren Operationen zum Durchlaufen von Fremdschlüsseln erforderlich. Es geht darum, den Hinweisen zu folgen.
Gemeinschaftliche Unterstützung
Realm befindet sich in aktiver Entwicklung und hat ziemlich oft aktualisierte Versionen veröffentlicht.
Alle Komponenten der Realm Mobile Database sind Open Source. Sie reagieren sehr schnell auf ihren Issue-Tracker und Stack Overflow, sodass Sie auf diesen Kanälen guten und schnellen Support erwarten können.
Außerdem wird das Feedback der Community bei der Priorisierung von Problemen berücksichtigt (Fehler, Verbesserungen, Funktionsanfragen usw.). Es ist immer gut zu wissen, dass Sie bei der Entwicklung der von Ihnen verwendeten Tools mitreden können.
Ich habe 2015 angefangen, Realm zu verwenden, und seitdem bin ich im Internet auf mehrere Posts mit unterschiedlichen Meinungen zu Realm gestoßen. Wir werden bald über seine Einschränkungen sprechen, aber eine Sache, die mir aufgefallen ist, ist, dass viele der zum Zeitpunkt des Posts vorgebrachten Beschwerden inzwischen behoben wurden.
Als ich zum Beispiel Realm kennenlernte, gab es noch keine Unterstützung für benutzerdefinierte Methoden auf Modellen und asynchrone Aufrufe. Dies waren damals für viele Deal Breaker, aber beide werden derzeit unterstützt.
Diese Entwicklungsgeschwindigkeit und Reaktionsfähigkeit macht uns zuversichtlicher, dass wir nicht lange auf wichtige Funktionen warten müssen.
Einschränkungen
Wie bei allem im Leben besteht auch bei Realm nicht alles aus Rosen. Neben der bereits erwähnten Vererbungsbeschränkung sind weitere Mängel zu beachten:
Obwohl es möglich ist, dass mehrere Threads gleichzeitig aus der Datenbank lesen und in sie schreiben, können Realm-Objekte nicht zwischen Threads verschoben werden . Wenn Sie also beispielsweise ein Realm-Objekt mit
doInBackground()
von AsyncTask abrufen, das in einem Hintergrund-Thread läuft, können Sie diese Instanz nicht an dieonPostExecute()
-Methoden übergeben, da diese im Haupt-Thread laufen. Mögliche Problemumgehungen für diese Situation wären, entweder eine Kopie des Objekts zu erstellen und weiterzugeben oder die ID des Objekts weiterzugeben und das Objekt erneut aufonPostExecute()
. Realm bietet synchrone und asynchrone Methoden zum Lesen/Schreiben.Es gibt keine Unterstützung für Primärschlüssel mit automatischer Inkrementierung , also müssen Sie sich selbst um deren Generierung kümmern.
Es ist nicht möglich, gleichzeitig von unterschiedlichen Prozessen aus auf die Datenbank zuzugreifen . Laut ihrer Dokumentation wird die Unterstützung für mehrere Prozesse in Kürze verfügbar sein.
Realm ist die Zukunft mobiler Datenbanklösungen
SQLite ist eine solide, robuste und bewährte Datenbank-Engine, und relationale Datenbanken werden so schnell nicht verschwinden. Es gibt eine Reihe guter ORMs, die auch für viele Szenarien geeignet sind.
Es ist jedoch wichtig, sich über aktuelle Trends auf dem Laufenden zu halten.
In dieser Hinsicht denke ich, dass Realm einer der größten kommenden Trends der letzten Jahre ist, wenn es um die Entwicklung mobiler Datenbanken geht.
Realm bringt einen einzigartigen Ansatz mit sich, um mit Daten umzugehen, die für Entwickler wertvoll sind, nicht nur, weil sie eine bessere Option als bestehende Lösungen sein können, sondern auch, weil sie unseren Horizont in Bezug auf neue Möglichkeiten erweitern und die Messlatte für mobile Datenbanktechnologie höher legen.
Hast du bereits Erfahrung mit Realm? Bitte zögern Sie nicht, Ihre Gedanken zu teilen.