将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
相关产品推荐
相关产品推荐

