0

I am working on a javafx application. Since I need to display some data from my database, I came to know about using Task in Javafx. I tried implementing it after seeing a solution on SO. To check if it works, I am just printing a list of teams which I get from my database in a HashTable.

When I first start the application, the data is successfully fetched and it displays on my console, but when I change through scenes and try to switch back to the homepage (where the data is being fetched), the UI totally freezes and it doesn't even display the scene.

Home.java

public class Home implements Initializable {

    private Executor executor;
    private TeamsDAO teamsDAO;

@Override
    public void initialize(URL url, ResourceBundle resourceBundle)  {

        try{
            teamsDAO = new TeamsDAO();
        }catch (SQLException e){
            e.printStackTrace();}

        executor = Executors.newCachedThreadPool(runnable -> {
            Thread th = new Thread(runnable);
            th.setDaemon(true);
            return th;
        });

        printTeams();
    }

public void printTeams() {
        Task<Hashtable<Integer, String>> displayTask = new Task<Hashtable<Integer, String>>() {
            @Override
            protected Hashtable<Integer, String> call() throws Exception {
                return teamsDAO.getTeams();
            }
        };

        displayTask.setOnFailed(e -> {
            displayTask.getException().printStackTrace();
        });

        displayTask.setOnSucceeded(e -> {
            cricProTitle.setText(displayTask.getValue().get(2));
        });

        executor.execute(displayTask);
    }
}

I am using HikariCP for database connection pool with postgresql.

TeamsDAO.java

public class TeamsDAO {

    private Connection conn;

    public TeamsDAO() throws SQLException {
        this.conn = DataSource.getConnection();
    }

    public Hashtable<Integer, String> getTeams() throws SQLException {
        try (PreparedStatement pst = conn.prepareStatement("SELECT * FROM TEAMS")) {
            ResultSet rs = pst.executeQuery();
            Hashtable<Integer, String> teams = new Hashtable<>();
            while (rs.next()) {
                teams.put(rs.getInt("team_id"), rs.getString("name"));
            }
            return teams;
        }
    }
}

No error stack trace is displayed when the UI freezes. I would like these teams to be displayed on the homepage (after the thread works successfully) . Please suggest where am I going wrong?

Ali Ahmed
  • 164
  • 2
  • 12
  • Maybe this will help? [Concurrency in JavaFX](https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm) – Abra Dec 18 '21 at 15:17
  • Thanks, but I have already been through it. Even after changing my code according to the tutorial, the task executes successfully only once :(. – Ali Ahmed Dec 18 '21 at 15:24
  • 3
    “…when I change through scenes and try to switch back to the homepage (where the data is being fetched), the UI totally freezes…” Since that seems to be what’s causing the problem, I recommend editing your question and including the code which does that. – VGR Dec 18 '21 at 15:41
  • 4
    [mcve] please (hard-code the data fetching in the thread, sleeping as needed) .. – kleopatra Dec 18 '21 at 15:44
  • 1
    Run it in a debugger. Step through the code. Check what threads are blocked and where. – swpalmer Dec 18 '21 at 19:54
  • 1
    Thank you for the suggestions, the problem occurred due to switching scenes and reloading them again and again, which was creating new threads and filling up the Database connection pool. – Ali Ahmed Dec 18 '21 at 20:28
  • You could [self-answer](https://stackoverflow.com/help/self-answer) if you want. – jewelsea Dec 18 '21 at 21:53

1 Answers1

1

As I was initiating the TeamsDAO object in initialize method, It was creating a new database connection every time I switched back to Home controller, and hence filling up the connection pool. To fix this I created a static block in Home.java and fetched the data I needed only once.

Updated Home.java:

public class Home implements Initializable {

    private static TeamsDAO teamsDAO;

    @FXML
    private BorderPane borderPane;
    @FXML
    private Label cricProTitle;
    @FXML
    private Label homepageLabel;
    @FXML
    private Label banner;
    @FXML
    private GridPane buttonContainer;

    static {
        try {
            teamsDAO = new TeamsDAO();
        } catch (SQLException e) {
            e.printStackTrace();
        }

        Task<Hashtable<Integer, String>> task = new Task<>() {
            @Override
            protected Hashtable<Integer, String> call() throws Exception {
                return teamsDAO.getTeams();
            }
        };

        task.setOnSucceeded(e -> {
            System.out.println(task.getValue());
        });

        Thread x = new Thread(task);
        x.setDaemon(true);
        x.start();
        System.out.println(x.getState());
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle)  {
    //setting UI properties here..
    }

}

Zoe
  • 27,060
  • 21
  • 118
  • 148
Ali Ahmed
  • 164
  • 2
  • 12
  • 1
    Thanks for posting an answer. You might be interested in the [eden coding guide on how to structure a JavaFX database application](https://edencoding.com/connect-javafx-with-sqlite/#how-to-structure-a-javafx-database-application). The guide also refers to a [GitHub repository](https://github.com/edencoding/javafx-io/tree/master/sqlite) so that you can see a complete example of the suggested approach. – jewelsea Dec 21 '21 at 04:34