【问题标题】:How the performance of a JavaFx-MySQL application can be enhanced如何增强 JavaFx-MySQL 应用程序的性能
【发布时间】:2023-04-10 12:10:01
【问题描述】:

在我的 JavaFx 应用程序中,我在单击按钮时加载一个 ObservableList,然后在表格中显示该列表。

控制器代码:

 @FXML
   private void initialize() throws SQLException, ParseException, ClassNotFoundException {

    searchChoice.setItems(criteriaList);
    searchChoice.getSelectionModel().selectFirst();
    productIdColumn.setCellValueFactory(cellData -> cellData.getValue().productIdProperty());
    unitColumn.setCellValueFactory(cellData -> cellData.getValue().unitProperty());
    productTitleColumn.setCellValueFactory(cellData -> cellData.getValue().titleProperty());
    productTypeColumn.setCellValueFactory(cellData -> cellData.getValue().typeProperty());
    productUnitPriceColumn.setCellValueFactory(cellData -> Bindings.format("%.2f", cellData.getValue().unitPriceProperty().asObject()));
    productQuantityColumn.setCellValueFactory(cellData -> cellData.getValue().quantityProperty().asObject());
    productStatusColumn.setCellValueFactory(cellData -> cellData.getValue().productStatusProperty());
    descriptionColumn.setCellValueFactory(cellData -> cellData.getValue().descriptionProperty());
    reorderPointColumn.setCellValueFactory(cellData -> cellData.getValue().reOrderPointProperty().asObject());
    surplusPointColumn.setCellValueFactory(cellData -> cellData.getValue().surplusPointProperty().asObject());
    productIdColumn.setSortType(TableColumn.SortType.DESCENDING);
    productTable.getSortOrder().add(productIdColumn);

    productTable.setRowFactory(tv -> new TableRow<Product>() {
        @Override
        public void updateItem(Product item, boolean empty) {
            super.updateItem(item, empty);
            if (item == null) {
                setStyle("");
            } else if (item.getQuantity() < item.getReOrderPoint()) {
                setStyle("-fx-background-color: tomato;");
            }  else if (item.getQuantity() > item.getSurplusPoint()) {
                setStyle("-fx-background-color: darkorange;");
            } else {
                setStyle("-fx-background-color: skyblue;");
            }
        }
    });

    try {
        ObservableList<Product> productData = ProductDAO.searchProducts();
        populateProducts(productData);
        String[] expireDate = new String[productData.size()];
        String[] id = new String[productData.size()];
        String[] existingStatus = new String[productData.size()];
        for (int i = 0; i < productData.size(); i++) {
            expireDate[i] = productData.get(i).getExpireDate();
            id[i] = productData.get(i).getProductId();
            existingStatus[i] = productData.get(i).getProductStatus();
            DateFormat format = new SimpleDateFormat(app.values.getProperty("DATE_FORMAT_PATTERN"), Locale.ENGLISH);
            Date expireDateString = format.parse(expireDate[i]);
            Date in = new Date();
            LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
            Date today = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
            if (expireDateString.before(today) && !existingStatus[i].equals(app.values.getProperty("STATUS_TYPE2"))) {
                ProductDAO.updateProductStatus(id[i], app.values.getProperty("STATUS_TYPE3"));
            }
            if (expireDateString.after(today) && !existingStatus[i].equals(app.values.getProperty("STATUS_TYPE2"))) {
                ProductDAO.updateProductStatus(id[i], app.values.getProperty("STATUS_TYPE1"));
            }
        }
        ObservableList<Product> productDataRefreshed = ProductDAO.searchProducts();
        populateProducts(productDataRefreshed);

        ObservableList<Product> productCodesData = ProductDAO.getProductCodes();
        ObservableList<Product> productTitlesData = ProductDAO.getProductTitles();
        ObservableList<Product> productTypesData = ProductDAO.getProductTypes();
        ObservableList<Product> productStatusData = ProductDAO.getProductStatus();
        String possibleProducts1[] = new String[productCodesData.size()];
        for (int k = 0; k < productCodesData.size(); k++) {
            possibleProducts1[k] = productCodesData.get(k).getProductId();
        }
        String possibleProducts2[] = new String[productTitlesData.size()];
        for (int k = 0; k < productTitlesData.size(); k++) {
            possibleProducts2[k] = productTitlesData.get(k).getTitle();
        }
        String possibleProducts3[] = new String[productTypesData.size()];
        for (int k = 0; k < productTypesData.size(); k++) {
            possibleProducts3[k] = productTypesData.get(k).getType();
        }

        String possibleProducts4[] = new String[productStatusData.size()];
        for (int k = 0; k < productStatusData.size(); k++) {
            possibleProducts4[k] = productStatusData.get(k).getProductStatus();
        }

        TextFields.bindAutoCompletion(searchField, possibleProducts1);
        TextFields.bindAutoCompletion(searchField, possibleProducts2);
        TextFields.bindAutoCompletion(searchField, possibleProducts3);
        TextFields.bindAutoCompletion(searchField, possibleProducts4);

    } catch (SQLException e) {
        Alert alert = new Alert(Alert.AlertType.ERROR);
        alert.setTitle(app.values.getProperty("ERROR_TITLE"));
        alert.setHeaderText(app.values.getProperty("FAILURE_MESSAGE"));
        alert.setHeaderText(app.values.getProperty("ERROR_GETTING_INFORMATION_FROM_DATABASE_MESSAGE"));
        alert.showAndWait();
        throw e;
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

}

服务mysql查询:

  public static ObservableList<Product> searchProducts() throws SQLException, ClassNotFoundException {
    String selectStmt = "SELECT * FROM product";
    ResultSet rsPrdcts = DbUtil.dbExecuteQuery(selectStmt);
    ObservableList<Product> productList = getProductList(rsPrdcts);
    return productList;
}

这里的问题是,当列表中有超过 200-300 个项目时,场景的加载速度非常慢。对此我可以采取什么对策?任何想法将不胜感激。 提前致谢。

【问题讨论】:

  • 这个问题更适合codereview.stackexchange.com
  • 如果性能很重要,请使用 ObservableMap 而不是 ObservableList
  • 我找到了一个非常好的实现示例。你可能会从这篇文章中受益。 stackoverflow.com/questions/16941980/…
  • 您可以将数据从数据库加载到不同的线程。否则你可能无能为力(假设与数据库的连接是这里的瓶颈)。
  • 我已经加载了 200-300 多件零问题的物品。我猜你的for-loop -> for (int i = 0; i &lt; productData.size(); i++) 是问题所在。这包括所有其他for-loops

标签: mysql performance javafx load-time


【解决方案1】:

您需要实现一个ObservableList,它只检索由TableView 请求的数据。目前,您检索表中的所有元素并将检索到的列表转换为ObservableListTableView 使用OL 的.get(int idx) 方法检索所有应显示的项目,并使用.size() 方法确定滚动条的大小。当您滚动时TableView 将丢弃所有未显示的项目并再次调用 get 方法。

要解决您的问题需要创建一个implements ObservableList&lt;E&gt; 的类。首先,您需要实现.get(int idx).size() 方法,对于所有其他方法,我将throw new UnsupportedOperationException() 稍后查看还需要哪些其他方法。所以.size()方法需要执行如下查询

SELECT count(*) FROM product

还有get(int idx) 类似的东西

int numItems = 30;
int offset = idx - (idx % numItems)
SELECT * FROM product LIMIT offset, numItems

您可以创建一个内部列表,该列表仅包含例如来自您的数据库的 30 个项目,每当请求的 idx &lt; offset || idx &gt; offset + numItems 您发出新的数据库请求时。

我将这种方法用于具有数百万行的数据库表,并且具有非常高性能的 GUI。您还可以将分页添加到 TableView,因为滚动条有很多行变得无用,但这是一个不同的讨论。

编辑:

我忘了说这个叫Lazy Loading

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-31
    • 1970-01-01
    • 2012-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多