JavaFX Verzögerung beim Laden von Daten

lam_tr

Top Contributor
Hallo zusammen,

ich habe ein Problem, dass ich ca. 30000 Datensätze per Hibernate auf ein Datenbank in die UI laden muss. Gibt es einen weg das zu machen dass die UI nicht einfriert. Momentan mache ich es über einen Button der direkt die Abfrage macht und die Daten in einer Tabelle darstellt.

Ich habe gehört von separaten UI Thread.

Ist das richtig so, oder wie geht man da vor?

Viele Grüße
lam
 
Das ist richtig. Wie du schon erkannt hast friert der Application Thread deiner Anwendung ein wenn du zuviel machst... qed : neuer Thread 🙂
 
Operationen die länger brauchen bei der Ausführung sollten nicht im UI Thread (EDT) ausgeführt werden, daher kommt das einfrieren der UI (der Thread ist mit dem auslesen der DB beschäftigt und kann daher nichts neuzeichnen). Stichwörter zu diesem Thema: EventDispatcherThread, SwingWorker, ... (natürlich vorrausgesetzt es handelt sich dabei um Swing, wie es bei JavaFX genau ist weiß ich nicht).

Anmerkung: Es macht keinen Sinn 30000 Datensätze aus der DB zu lesen und anzeigen zulassen. Zeig mir den Bildschirm der sinnvoll alle diese Datensätze auf einmal darstellen kann. Daher lade immer nur einen bestimmten Teil der Daten in den Speicher.
Beispiel: Du hast eine Liste welche dir ca 30 Datensätze auf einmal anzeigen kann. Anstatt nun alle 30000 Datensätze zu laden, ladest du nur maximal 90 Datensätze.
30 Datensätze können angezeigt werden, die anderen 60 dienen jeweils als "Buffer" für ein sauberes scrollen. Sobald du scrollst werden im Hintergrund eben entsprechend viele Datensätze nachgeladen.

Sind die 30000 Datensätze nicht als eine Liste zu sehen sondern komplexe Objekte inkl Beziehungen dann solltest du dir LazyLoading anschauen. Da werden die Daten erst vollständig geladen wenn benötigt.
Beispiel: Du hast eine Liste mit ein paar hundert Einträgen + ein Detailfenster für den aktuell ausgewählten Eintrag. Anstatt zu allen Einträgen in der Liste die kompletten Details zu laden, wird nur die Liste geladen und erst wenn du einen entsprechenden Eintrag auswählst werden die restlichen Daten aus der DB geladen.
 
Hallo Joose,

vielen Dank für die ausführliche Erklärung. Lazy Loading hört sich sehr gut an. Wie kann ich das an sich realisieren?

Mir fehlt momentan der Gedanke iw eich es umsetzen soll. Du hast mir zwar Gedankenzüge erklärt. Also wenn ich in der Tabelle zum Beispiel die ersten 90 Einträge anzeigen soll, und genau an der Stelle hänge ich, wie lade ich die ersten 90 per Select? Die 90 ersten aktuellen, und wenn ich runtergescrollt habe zum letzten die Einschränkung vom ab 90 aktuellen bis 180 aktuellsten? Und das ganze wieder rückwärts?

Es hört sich auf jeden Fall sehr aufwändig an.

Kannst du mir noch weitere Tipps dazu geben`?

Viele Grüße
lam
 
Achtung: Ich habe es etwas vermischt 😉
Eager und LazyLoading beziehen sich im großen und ganzen auf die Vollständigkeit der Datensätze.
Das "vorladen" von Datensätze wäre ein Art Buffer.

Beispiel MySql:
In einem einfache SQL Select kannst du mittels "LIMIT [Anzahl]" bzw. "LIMIT [Index], [Anzahl]" die Ergebnismenge begrenzen. Je nach SQL Dialekt kann es auch MAX ROWS oder ähnliches sein.
Ob es in Hibernate eine alternative dafür gibt weiß ich leider nicht.
 
JavaFX zeigt hat einen eigenen Abschnitt zu Concurrency:
https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm

Hier kannst du sehen, das du die "observierbaren" Klassen

- Task (eine Erweiterung von "Future", die du wie einen Thread nutzen kannst, die dir aber noch ein paar Livecycle-Events spendiert, an die du dich anhängen kannst)
- und Service (mit einer Methode, einen Task zu erstellen und das direkt einen Executor mitbringt - kannst also theoretisch schnell hintereinander Aufgaben starten und deren Ergebnis verarbeiten - auch hier bringt Service einige Methoden mit, wo du dich registrieren kannst)

verwenden kannst, um deine Arbeit nicht auf dem UI-Thread durchzuführen.

Ich habe rein mit Tasks gearbeitet, um meine DB-(SQLite-)Abfragen vom UI zu trennen, du musst dann auf das Success/Fail/Canceled hören. Oder du schiebst zwischendurch schon Daten in eine Oberservable rein (aber dann musst du darauf achten, dass du es mit Platform#runLater machst, wenn du es direkt aus dem Task heraus auslöst - sinnvoll nur, wenn du einen Prozess mit Zwischeergebnissen hast, die nicht einen rein auf Double basierten Fortschritt der Operation darstellen).

Siehe auch:
https://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html
https://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Service.html
 

Zurück
Oben