While populating the ObservableList, do I need to load ALL records from my database?

So I am porting my Java Swing Java application to Java FX (still a newbie here, I recently just learned the basics of FXML and the MVC pattern, so please bear with me).

I intend to load data from my existing database into a "student" ObservableList so I can show it in a TableView, but in my Swing source code I have a text TextField and when the user clicks a button or press Enter, the program:

  • Runs a SQLite command that searches for specific records and retrieves the RecordSet.
  • Creates a DefaultTableModel template based on the contents of the RecordSet.
  • And issues this TableModel to a JTable.

However, Java FX is a completely different beast (or at least I don't think it is, I don't like me, I like Java FX: D), so I'm not sure what to do.

So my question is, do I need to load ALL students into a database and then use some Java code to filter out students that don't match the search criteria (and display all students when the search text is empty), or am I still using SQLite to filter and fetching records (which means I need to clear the list and then add students every time the search is done and maybe this will mess up the bindings as well? Perhaps there will be a speed penalty for this method too? Also, it will also reset the selected at the moment of writing, because I am clearing the list - mostly bad UI design and negatively impacting usability)

Depending on the correct approach, there is also the following question (sorry, I really cannot find an answer to them even after Googling):

  • If I get ALL students from a database and implement the search function in Java, wouldn't it use more RAM than it needs because I store ALL database data in RAM, not just what I was looking for? I mean, of course, even my humble laptop has 4GB of RAM, but the feeling of using more memory than me should make me feel a little guilty. Lol
  • If I just want to update the content of the ObservableList every time a new search is done, will it get corrupted by links? Do I need to tweak the bindings again? How do I clear the content of the ObservableList before adding new content?

I also have an idea to just set the selected table item to the first record that matches the search string, but I think it will be difficult to use since only one record can be highlighted for each search. Even if we select multiple lines, it will be difficult to see all the selected items.

Please give me the right way, not the "easy" way. This is my first time I implement a pattern (MVC, or I really do MVP, I don't know) and I realized how irreplaceable and ugly my previous programs are because I used my own style. This is a relatively large project that I need to maintain and improve over the years in order to have clean code and do something the right way to help maintain the functionality of this program.

Thanks in advance for your help, and I hope I don't get obsessed with being a "dumb person who can't even Google" ask these questions. Please carry me here.

+3


source to share


1 answer


Basic project calculations

You can, of course, do this in one way of describing it. Major trade-offs:

  • If you load everything from the database and filter the table in Java, you are using more memory (although not as much as you might think, as described below).
  • If you are filtering from the database and reloading every time the user changes the filter, there will be a large delay (latency) in displaying the data as the new query will be executed on the database with (usually) a network connection between the database and the application being the most a big bottleneck (although there are others).

Database access and concurrency

In general, you should run database queries on a background thread (see Using Threads to Create Database Queries ); if you make frequent queries to the database (i.e. filtering through the database) this gets tricky and includes frequent disabling of UI controls when a background task is running.

TableView

design and memory management

JavaFX TableView

is a virtualized control. This means that visual components (cells) are only created for visible elements (plus maybe a small amount of caching). These cells are then reused as the user scrolls to display various "items" as needed. Visual components tend to be quite memory-heavy (they have hundreds of properties - colors, font properties, sizes, layout properties, etc.), most of which have CSS views), so limiting the number generated saves a lot of memory and the memory of the visible portion of the table view is essentially constant, no matter how many items are in the table's backing list.

General memory consumption calculations

The observable list items

that forms the table backing list contains only data: it is not hard to estimate the approximate amount of memory consumed by a list of a given size. String

use 2 bytes per character, and also a little fixed overhead, double

use 8 bytes, int

use 4 bytes, etc. If you put fields in JavaFX properties (which is recommended), there will be multiple bytes for each one; each object has ~ 16 bytes overhead, and the links themselves usually use up to 8 bytes. Thus, a typical objectStudent

which stores multiple string fields typically consumes on the order of several hundred bytes in memory (Of course, if everyone has an image associated with it, for example, it could be much larger.) So if you load, say, 100,000 students from a database, you would be using on the order of 10-100 MB of RAM, which is pretty manageable. on most personal computer systems.

Rough general guidelines

Generally, for the type of application being described, I would recommend loading what's in your database and filtering it in memory. In my usual field of work (genomics), where we sometimes need 10 or 100 million people, this is not possible. (If your database contains, say, all enrolled students in US public schools , you might run into similar problems.)



However, as a rule of thumb, for a "normal" object (that is, one that does not have large data objects, such as images associated with it), the size of your table will be too large for the user to be able to comfortably manipulate (even with filtering) before you will seriously expand the memory capacity of the user's machine.

Filtering a table in Java (all objects in memory)

Filtering in your code is pretty straightforward. In short, you load everything in ObservableList

and wrap ObservableList

in FilteredList

. A FilteredList

wraps the original list and Predicate

, which returns true

, the element must pass the filter (to be included) or false if excluded.

Thus, the code snippets you would use might look like this:

ObservableList<Student> allStudents = loadStudentsFromDatabase();
FilteredList<Student> filteredStudents = new FilteredList<>(allStudents);
studentTable.setItems(filteredStudents);

      

And then you can change the predicate based on the textbox with code like:

filterTextField.textProperty().addListener((obs, oldText, newText) -> {
    if (newText.isEmpty()) {
        // no filtering:
        filteredStudents.setPredicate(student -> true);
    } else {
        filteredStudents.setPredicate(student -> 
            // whatever logic you need:
            student.getFirstName().contains(newText) || student.getLastName().contains(newText));
    }
});

      

This tutorial takes a closer look at filtering (and sorting) tables.

Comments on the implementation of "query filtering"

If you don't want to load everything from the database, you are skipping the filtered list entirely. The database query will almost certainly not run fast enough to filter (using a new database query) as the user enters types, so you need an Update button (or an action listener on a text box) that recalculates the new filtered data ... You will probably need to do this on a background thread as well. You didn't need to set new cellValueFactory

(or cellFactory

s) on table columns or reload columns; you just call studentTable.setItems(newListOfStudents);

when the database query is complete.

+4


source







All Articles