You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将JavaFX进度条与Hibernate数据加载方法结合实现

给Hibernate数据加载方法添加JavaFX进度条的解决方案

我来帮你搞定这个进度条需求!你的原代码直接在UI线程里执行数据库查询和字符串拼接,这会导致界面卡顿甚至假死——因为JavaFX的UI操作必须在JavaFX应用线程完成,而耗时的数据库操作会阻塞这个线程。我们可以用JavaFX的Task类把耗时操作放到后台线程,同时安全地更新进度条和文本区域。

修改后的完整代码

@FXML private JFXProgressBar progressBar;
@FXML private JFXTextArea textArea;

@FXML void executeQuery(MouseEvent event) {
    // 创建后台任务,处理数据库查询与进度更新
    Task<String> loadDataTask = new Task<String>() {
        @Override
        protected String call() throws Exception {
            // 后台线程执行数据库操作:此处绝对不能直接操作UI控件
            EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("firebird_config_file");
            EntityManager entityManager = entityManagerFactory.createEntityManager();
            
            try {
                TypedQuery<Programy> query1 = entityManager.createQuery("select p from Programy p", Programy.class);
                List<Programy> programList = query1.getResultList();
                int totalItems = programList.size();
                StringBuilder resultBuilder = new StringBuilder(); // 用StringBuilder提升大字符串拼接效率
                
                int currentIndex = 0;
                for (Programy programy : programList) {
                    // 拼接单条数据字符串
                    String tmp = "Nazwa programu: " + programy.getExeNazwa() + 
                                 " Kod programu: " + programy.getKodProg() + 
                                 " Wersja: " + programy.getWersja() + "\n";
                    resultBuilder.append(tmp);
                    
                    // 实时更新进度:当前处理项数/总项数
                    currentIndex++;
                    updateProgress(currentIndex, totalItems);
                    
                    // 可选:如果想看到更明显的进度变化,可添加微小延迟(生产环境无需此代码)
                    // Thread.sleep(10);
                }
                
                return resultBuilder.toString();
            } finally {
                // 确保关闭数据库资源,避免内存泄漏
                entityManager.close();
                entityManagerFactory.close();
            }
        }
    };

    // 绑定进度条到任务的进度属性,实现自动更新
    progressBar.progressProperty().bind(loadDataTask.progressProperty());
    
    // 任务成功完成后,在UI线程更新文本区域
    loadDataTask.setOnSucceeded(e -> {
        textArea.setText(loadDataTask.getValue());
        // 任务完成后解绑进度条,并设置为100%状态
        progressBar.progressProperty().unbind();
        progressBar.setProgress(1.0);
    });
    
    // 处理任务失败场景(比如数据库连接错误)
    loadDataTask.setOnFailed(e -> {
        textArea.setText("加载数据失败:" + loadDataTask.getException().getMessage());
        progressBar.progressProperty().unbind();
        progressBar.setProgress(0.0);
    });
    
    // 启动后台任务:必须用Thread包装后启动
    new Thread(loadDataTask).start();
}

关键要点说明

  • Task类的作用:call()方法内的代码在后台线程执行,不会阻塞UI;updateProgress()是线程安全的方法,会自动把进度更新发送到UI线程。
  • 进度计算逻辑:先获取查询结果的总数量,循环时每处理一项就更新进度比例,让进度条平滑显示加载状态。
  • UI操作安全性:setOnSucceeded和setOnFailed内的代码运行在JavaFX应用线程,所以可以安全操作textArea和progressBar。
  • 资源清理:用finally块确保EntityManager和EntityManagerFactory被关闭,避免数据库连接泄漏。
  • 性能优化:用StringBuilder替代直接拼接String,在处理大量数据时能大幅减少内存开销和提升效率。

额外注意事项

  • 绝对不要在call()方法内直接操作UI控件,否则会抛出IllegalStateException。
  • 如果查询结果量极大,可以考虑分页加载,避免一次性把所有数据加载到内存中。
  • 在查询还未拿到结果列表时,可以设置progressBar.setProgress(-1.0);,让进度条显示“不确定进度”的转圈效果。

内容的提问来源于stack exchange,提问作者Rocky3582

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:32:25