9.9 KiB
9.9 KiB
导入进度显示优化说明
❌ 问题现象
- 导入100条数据,进度不显示或显示很慢
- 中断导入时显示"没有导入任何成功或失败的数据"
- 看不到正在做什么
🔍 问题原因
原因1:进度更新频率太低
int updateInterval = 100; // 每100条更新一次
问题:
- 100条数据只更新2次进度(第100条和结束时)
- 前99条处理时用户看不到任何进度
- 导致用户以为系统卡死
原因2:中断时结果保存不正确
// 只设置了progress.setResult()
// 但没有调用progressManager的方法保存
progress.setResult(resultMsg.toString());
return; // 直接return,结果丢失
原因3:缺少详细的处理日志
// 只有进度日志
logger.info("任务 {} 进度更新: {}/{}", taskId, i, totalSize);
// 缺少:
// - 正在处理哪条记录
// - 新增还是更新
// - 处理结果如何
✅ 解决方案
优化1:提高进度更新频率
修改前:
int updateInterval = 100; // 每100条更新一次
修改后:
int updateInterval = 5; // 每5条更新一次
效果:
- 100条数据会更新20次进度
- 用户每处理5条就能看到进度变化
- 实时反馈,体验更好
优化2:修复中断时的结果保存
修改前:
com.ddnai.common.core.domain.ImportProgress progress = progressManager.getProgress(taskId);
if (progress != null) {
progress.setResult(resultMsg.toString());
}
return; // 结果可能丢失
修改后:
// 使用progressManager的方法保存结果
progressManager.cancelTask(taskId, resultMsg.toString());
return;
效果:
- 中断时正确保存已处理的结果
- 显示新增、更新、失败的具体数量
- 显示失败的详细信息
优化3:添加详细的处理日志
新增用户时:
logger.info("正在新增用户: 信息编号={}, 姓名={}", infoNo, prisonerName);
userMapper.insertUser(user);
logger.info("用户新增成功: 信息编号={}, userId={}", infoNo, user.getUserId());
更新用户时:
logger.info("正在更新用户: 信息编号={}, 姓名={}", infoNo, prisonerName);
userMapper.updateUser(u);
logger.info("用户更新成功: 信息编号={}", infoNo);
进度更新时:
String progressInfo = String.format("[%d/%d] 新增:%d 更新:%d 失败:%d 跳过:%d",
i + 1, totalSize, successNum, updateNum, errorNum, duplicateNum);
logger.info("任务 {} 进度: {}", taskId, progressInfo);
📊 优化效果对比
优化前
| 项目 | 表现 |
|---|---|
| 进度更新 | 100条只更新2次 |
| 进度显示 | 99条时看不到进度 |
| 中断显示 | "没有导入任何数据" |
| 日志详细度 | 只有简单进度 |
优化后
| 项目 | 表现 |
|---|---|
| 进度更新 | 100条更新20次 |
| 进度显示 | 每5条就能看到 |
| 中断显示 | 显示已处理的详情 |
| 日志详细度 | 每条记录都有日志 |
📋 修改内容
文件: StudyClassUserServiceImpl.java
修改1:进度更新频率(第905行)
// 每处理5条更新一次进度(让用户看到实时进度)
int updateInterval = 5;
修改2:中断时保存结果(第936行)
// 保存取消状态和结果
progressManager.cancelTask(taskId, resultMsg.toString());
修改3:新增详细日志(第998-1000行)
logger.info("正在新增用户: 信息编号={}, 姓名={}", infoNo, prisonerName);
userMapper.insertUser(user);
logger.info("用户新增成功: 信息编号={}, userId={}", infoNo, user.getUserId());
修改4:更新详细日志(第1092-1094行)
logger.info("正在更新用户: 信息编号={}, 姓名={}", infoNo, prisonerName);
userMapper.updateUser(u);
logger.info("用户更新成功: 信息编号={}", infoNo);
修改5:进度日志格式(第1235-1237行)
String progressInfo = String.format("[%d/%d] 新增:%d 更新:%d 失败:%d 跳过:%d",
i + 1, totalSize, successNum, updateNum, errorNum, duplicateNum);
logger.info("任务 {} 进度: {}", taskId, progressInfo);
🔧 部署步骤
步骤1:重新编译
cd C:\Users\Administrator\Desktop\Project\ry_study-v_03\Study-Vue-redis
mvn clean package -DskipTests
步骤2:重启服务
停止旧服务,启动新服务
步骤3:测试导入
- 导入50条数据
- 观察进度是否实时更新
- 测试中断功能
- 查看日志详细程度
🧪 测试场景
场景1:正常导入
操作:
- 导入100条数据
- 观察进度条
预期:
- 进度条从0%逐步增加到100%
- 每5条更新一次(约每秒更新几次)
- 最终显示成功数量
日志示例:
正在新增用户: 信息编号=201, 姓名=张三
用户新增成功: 信息编号=201, userId=1001
任务 xxx 进度: [5/100] 新增:5 更新:0 失败:0 跳过:0
正在新增用户: 信息编号=206, 姓名=李四
用户新增成功: 信息编号=206, userId=1006
任务 xxx 进度: [10/100] 新增:10 更新:0 失败:0 跳过:0
...
场景2:中断导入
操作:
- 开始导入100条数据
- 处理到第30条时点击"中断导入"
预期:
- 显示中断提示
- 显示已处理30条的详情:
导入已取消! 新增: 20 条 更新: 8 条 失败: 2 条 无变化跳过: 0 条 未处理: 70 条 失败详情: 1、信息编号 205,罪犯姓名 王五 导入失败:班级 [三班] 不存在 2、信息编号 210,罪犯姓名 赵六 导入失败:监区不能为空
场景3:包含错误的导入
操作:
- 导入100条数据,其中20条班级不存在
预期:
- 进度实时更新
- 最终显示:
导入完成!新增:70条,更新:10条,失败:20条。 失败详情: 1、信息编号 205,罪犯姓名 张三 导入失败:班级 [三班] 不存在 ...(逐条列出20条失败记录)
日志示例:
正在新增用户: 信息编号=205, 姓名=张三
用户新增成功: 信息编号=205, userId=1005
为学员 205 分配班级时失败: 班级 [三班] 不存在,请先创建该班级
任务 xxx 进度: [5/100] 新增:4 更新:0 失败:1 跳过:0
📊 日志输出示例
完整的导入过程日志
[INFO] 任务 cce42e41-f819-4029-9c4e-0155fb3c2582 开始,共 100 条数据
[INFO] 预加载班级映射完成,共 5 个班级
[INFO] 正在新增用户: 信息编号=201, 姓名=张三
[INFO] 用户新增成功: 信息编号=201, userId=1001
[INFO] 为学员 201 分配班级 中级班1班 成功
[INFO] 正在新增用户: 信息编号=202, 姓名=李四
[INFO] 用户新增成功: 信息编号=202, userId=1002
[INFO] 为学员 202 分配班级 初级班1班 成功
[INFO] 正在新增用户: 信息编号=203, 姓名=王五
[INFO] 用户新增成功: 信息编号=203, userId=1003
[WARN] 为学员 203 分配班级时失败: 班级 [三班] 不存在,请先创建该班级
[INFO] 正在新增用户: 信息编号=204, 姓名=赵六
[INFO] 用户新增成功: 信息编号=204, userId=1004
[INFO] 为学员 204 分配班级 高级班1班 成功
[INFO] 正在新增用户: 信息编号=205, 姓名=孙七
[INFO] 用户新增成功: 信息编号=205, userId=1005
[INFO] 为学员 205 分配班级 攻坚转换班1班 成功
[INFO] 任务 xxx 进度: [5/100] 新增:5 更新:0 失败:0 跳过:0
[INFO] 正在更新用户: 信息编号=210, 姓名=周八
[INFO] 用户更新成功: 信息编号=210
[INFO] 为学员 210 更新班级为 中级班1班 成功
... (继续处理)
[INFO] 任务 xxx 进度: [10/100] 新增:8 更新:2 失败:0 跳过:0
[INFO] 任务 xxx 进度: [15/100] 新增:12 更新:3 失败:0 跳过:0
...
[INFO] 任务 xxx 进度: [100/100] 新增:70 更新:20 失败:5 跳过:5
[INFO] 任务 xxx 完成,最终结果:成功 70 条,更新 20 条,重复 5 条,失败 5 条
💡 进一步优化建议
1. 添加进度百分比
int percent = (i + 1) * 100 / totalSize;
logger.info("任务 {} 进度: {}% [{}]", taskId, percent, progressInfo);
2. 添加预计剩余时间
long elapsed = System.currentTimeMillis() - startTime;
long avgTime = elapsed / (i + 1);
long remaining = avgTime * (totalSize - i - 1);
logger.info("预计剩余时间: {} 秒", remaining / 1000);
3. 添加每秒处理速度
double speed = (i + 1) / (elapsed / 1000.0);
logger.info("处理速度: {:.1f} 条/秒", speed);
⚠️ 注意事项
1. 日志量增加
- 每条记录产生2-3条日志
- 100条数据约200-300条日志
- 建议定期清理日志文件
2. 性能影响
- 日志输出有一定性能开销
- 但相比数据库操作可忽略
- 如果追求极致性能,可以只在DEBUG级别输出详细日志
3. 进度更新频率
- 当前设置为每5条更新一次
- 可根据实际情况调整(3-10条都可以)
- 太频繁会增加网络开销
📋 验收标准
- 导入100条数据,进度实时更新(每5条更新)
- 进度条流畅增长,无卡顿
- 中断导入时显示已处理的详细信息
- 日志显示每条记录的处理过程
- 日志包含:正在处理、处理成功、失败原因
- 最终结果统计正确
✅ 总结
核心改进
- 进度更新频率从100条提高到5条
- 中断时正确保存和显示结果
- 添加详细的处理日志
用户体验
- ✅ 实时看到导入进度
- ✅ 知道正在处理什么
- ✅ 中断时有明确反馈
- ✅ 日志便于排查问题
开发调试
- ✅ 日志详细便于调试
- ✅ 可以追踪每条记录
- ✅ 快速定位性能瓶颈
现在重新编译并测试,应该能看到实时的进度更新和详细的处理日志了! 🚀