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

如何通过Java代码有效跟踪文件导入数据库的状态?

解决文件导入状态跟踪无响应问题

先看你代码里的核心问题:

  • 嵌套WatchService循环导致阻塞:捕获到文件删除事件后,你又开了一个watchService.take()循环,这个方法是阻塞式的,没有新文件系统事件就会一直卡着,根本不会执行数据库查询逻辑,自然看不到任何输出。
  • 轮询逻辑完全失效:内层循环卡死后,AtomicBoolean flag永远不会被设为false,直接进入死循环。
  • 时间计算逻辑错误:Duration.between(start,end).getSeconds()已经是秒数,你再用TimeUnit.MILLISECONDS.toSeconds()转换,相当于把秒数当成毫秒处理,结果完全不对。

下面是修正后的代码,核心思路是:捕获到文件删除事件后,定时轮询数据库,直到目标文件对应的记录状态变为completed,或者超时退出:

@EventListener
public void handleContextStart(ContextRefreshedEvent event) throws IOException, InterruptedException {
    System.out.println("Handling context started event.!!!");
    System.out.println("Running file verifier");
    System.out.println("monitoring folder " + folderPath);

    WatchService watchService = FileSystems.getDefault().newWatchService();
    Path path = Paths.get(folderPath);
    path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
    
    WatchKey key;
    while ((key = watchService.take()) != null) {
        for (WatchEvent<?> eventItem : key.pollEvents()) {
            System.out.println("Event kind:" + eventItem.kind() + ". File affected: " + eventItem.context() + ".");
            
            if (eventItem.kind().equals(StandardWatchEventKinds.ENTRY_DELETE)) {
                String deletedFileName = eventItem.context().toString();
                Instant start = Instant.now();
                boolean importCompleted = false;
                int retryCount = 0;
                final int MAX_RETRIES = 60; // 最多轮询60次(1分钟),可根据实际调整

                // 定时轮询数据库,直到状态变为completed或超时
                while (retryCount < MAX_RETRIES && !importCompleted) {
                    List<EntityImportRequestsTable> list = entityImportRequestsService.findAll();
                    for (EntityImportRequestsTable item : list) {
                        // 准确匹配文件名(避免包含导致的误判)
                        if (item.getRequestXmlSourceFile().endsWith(deletedFileName) 
                            && "completed".equals(item.getStatusCode())) {
                            System.out.println("File " + deletedFileName + " imported successfully!");
                            importCompleted = true;
                            break;
                        }
                    }
                    
                    if (!importCompleted) {
                        Thread.sleep(1000); // 每秒轮询一次
                        retryCount++;
                    }
                }

                // 计算并输出耗时
                Instant end = Instant.now();
                long totalSeconds = Duration.between(start, end).getSeconds();
                long minutes = totalSeconds / 60;
                long seconds = totalSeconds % 60;
                System.out.format("Execution time %d minutes %d seconds%n", minutes, seconds);
                
                if (!importCompleted) {
                    System.out.println("Warning: File " + deletedFileName + " import timed out!");
                }
            }
        }
        key.reset();
    }

    watchService.close();
}

关键修改说明:

  1. 移除内层WatchService循环,改用定时轮询数据库的方式,确保每次都能执行查询逻辑。
  2. 添加超时机制(MAX_RETRIES),避免无限等待。
  3. 优化文件名匹配逻辑:用endsWith替代contains,避免文件名包含相同子串导致的误判(比如"file1.xml"和"file11.xml")。
  4. 修正时间计算逻辑:直接用Duration的秒数计算分钟和剩余秒数,结果准确。
  5. 增加超时提示,方便排查导入失败的情况。

另外还要检查几个前置问题:

  • 确认folderPath配置正确,WatchService确实监听了目标文件夹。
  • 确认应用有该文件夹的读取权限,否则WatchService无法正常工作。
  • 确认entityImportRequestsService.findAll()能正确查询到数据库记录,必要时添加日志排查。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 12:05:30