如何通过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(); }
关键修改说明:
- 移除内层WatchService循环,改用定时轮询数据库的方式,确保每次都能执行查询逻辑。
- 添加超时机制(MAX_RETRIES),避免无限等待。
- 优化文件名匹配逻辑:用
endsWith替代contains,避免文件名包含相同子串导致的误判(比如"file1.xml"和"file11.xml")。 - 修正时间计算逻辑:直接用Duration的秒数计算分钟和剩余秒数,结果准确。
- 增加超时提示,方便排查导入失败的情况。
另外还要检查几个前置问题:
- 确认
folderPath配置正确,WatchService确实监听了目标文件夹。 - 确认应用有该文件夹的读取权限,否则WatchService无法正常工作。
- 确认
entityImportRequestsService.findAll()能正确查询到数据库记录,必要时添加日志排查。
内容的提问来源于stack exchange,提问作者Peter Penzov
相关产品推荐
相关产品推荐

