392 lines
9.9 KiB
Markdown
392 lines
9.9 KiB
Markdown
# 导入进度显示优化说明
|
||
|
||
## ❌ **问题现象**
|
||
|
||
1. 导入100条数据,进度不显示或显示很慢
|
||
2. 中断导入时显示"没有导入任何成功或失败的数据"
|
||
3. 看不到正在做什么
|
||
|
||
---
|
||
|
||
## 🔍 **问题原因**
|
||
|
||
### **原因1:进度更新频率太低**
|
||
```java
|
||
int updateInterval = 100; // 每100条更新一次
|
||
```
|
||
|
||
**问题:**
|
||
- 100条数据只更新2次进度(第100条和结束时)
|
||
- 前99条处理时用户看不到任何进度
|
||
- 导致用户以为系统卡死
|
||
|
||
### **原因2:中断时结果保存不正确**
|
||
```java
|
||
// 只设置了progress.setResult()
|
||
// 但没有调用progressManager的方法保存
|
||
progress.setResult(resultMsg.toString());
|
||
return; // 直接return,结果丢失
|
||
```
|
||
|
||
### **原因3:缺少详细的处理日志**
|
||
```java
|
||
// 只有进度日志
|
||
logger.info("任务 {} 进度更新: {}/{}", taskId, i, totalSize);
|
||
|
||
// 缺少:
|
||
// - 正在处理哪条记录
|
||
// - 新增还是更新
|
||
// - 处理结果如何
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ **解决方案**
|
||
|
||
### **优化1:提高进度更新频率**
|
||
|
||
**修改前:**
|
||
```java
|
||
int updateInterval = 100; // 每100条更新一次
|
||
```
|
||
|
||
**修改后:**
|
||
```java
|
||
int updateInterval = 5; // 每5条更新一次
|
||
```
|
||
|
||
**效果:**
|
||
- 100条数据会更新20次进度
|
||
- 用户每处理5条就能看到进度变化
|
||
- 实时反馈,体验更好
|
||
|
||
---
|
||
|
||
### **优化2:修复中断时的结果保存**
|
||
|
||
**修改前:**
|
||
```java
|
||
com.ddnai.common.core.domain.ImportProgress progress = progressManager.getProgress(taskId);
|
||
if (progress != null) {
|
||
progress.setResult(resultMsg.toString());
|
||
}
|
||
return; // 结果可能丢失
|
||
```
|
||
|
||
**修改后:**
|
||
```java
|
||
// 使用progressManager的方法保存结果
|
||
progressManager.cancelTask(taskId, resultMsg.toString());
|
||
return;
|
||
```
|
||
|
||
**效果:**
|
||
- 中断时正确保存已处理的结果
|
||
- 显示新增、更新、失败的具体数量
|
||
- 显示失败的详细信息
|
||
|
||
---
|
||
|
||
### **优化3:添加详细的处理日志**
|
||
|
||
**新增用户时:**
|
||
```java
|
||
logger.info("正在新增用户: 信息编号={}, 姓名={}", infoNo, prisonerName);
|
||
userMapper.insertUser(user);
|
||
logger.info("用户新增成功: 信息编号={}, userId={}", infoNo, user.getUserId());
|
||
```
|
||
|
||
**更新用户时:**
|
||
```java
|
||
logger.info("正在更新用户: 信息编号={}, 姓名={}", infoNo, prisonerName);
|
||
userMapper.updateUser(u);
|
||
logger.info("用户更新成功: 信息编号={}", infoNo);
|
||
```
|
||
|
||
**进度更新时:**
|
||
```java
|
||
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行)**
|
||
```java
|
||
// 每处理5条更新一次进度(让用户看到实时进度)
|
||
int updateInterval = 5;
|
||
```
|
||
|
||
#### **修改2:中断时保存结果(第936行)**
|
||
```java
|
||
// 保存取消状态和结果
|
||
progressManager.cancelTask(taskId, resultMsg.toString());
|
||
```
|
||
|
||
#### **修改3:新增详细日志(第998-1000行)**
|
||
```java
|
||
logger.info("正在新增用户: 信息编号={}, 姓名={}", infoNo, prisonerName);
|
||
userMapper.insertUser(user);
|
||
logger.info("用户新增成功: 信息编号={}, userId={}", infoNo, user.getUserId());
|
||
```
|
||
|
||
#### **修改4:更新详细日志(第1092-1094行)**
|
||
```java
|
||
logger.info("正在更新用户: 信息编号={}, 姓名={}", infoNo, prisonerName);
|
||
userMapper.updateUser(u);
|
||
logger.info("用户更新成功: 信息编号={}", infoNo);
|
||
```
|
||
|
||
#### **修改5:进度日志格式(第1235-1237行)**
|
||
```java
|
||
String progressInfo = String.format("[%d/%d] 新增:%d 更新:%d 失败:%d 跳过:%d",
|
||
i + 1, totalSize, successNum, updateNum, errorNum, duplicateNum);
|
||
logger.info("任务 {} 进度: {}", taskId, progressInfo);
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 **部署步骤**
|
||
|
||
### **步骤1:重新编译**
|
||
```bash
|
||
cd C:\Users\Administrator\Desktop\Project\ry_study-v_03\Study-Vue-redis
|
||
mvn clean package -DskipTests
|
||
```
|
||
|
||
### **步骤2:重启服务**
|
||
停止旧服务,启动新服务
|
||
|
||
### **步骤3:测试导入**
|
||
1. 导入50条数据
|
||
2. 观察进度是否实时更新
|
||
3. 测试中断功能
|
||
4. 查看日志详细程度
|
||
|
||
---
|
||
|
||
## 🧪 **测试场景**
|
||
|
||
### **场景1:正常导入**
|
||
|
||
**操作:**
|
||
1. 导入100条数据
|
||
2. 观察进度条
|
||
|
||
**预期:**
|
||
- 进度条从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:中断导入**
|
||
|
||
**操作:**
|
||
1. 开始导入100条数据
|
||
2. 处理到第30条时点击"中断导入"
|
||
|
||
**预期:**
|
||
- 显示中断提示
|
||
- 显示已处理30条的详情:
|
||
```
|
||
导入已取消!
|
||
新增: 20 条
|
||
更新: 8 条
|
||
失败: 2 条
|
||
无变化跳过: 0 条
|
||
未处理: 70 条
|
||
|
||
失败详情:
|
||
1、信息编号 205,罪犯姓名 王五 导入失败:班级 [三班] 不存在
|
||
2、信息编号 210,罪犯姓名 赵六 导入失败:监区不能为空
|
||
```
|
||
|
||
---
|
||
|
||
### **场景3:包含错误的导入**
|
||
|
||
**操作:**
|
||
1. 导入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. 添加进度百分比**
|
||
```java
|
||
int percent = (i + 1) * 100 / totalSize;
|
||
logger.info("任务 {} 进度: {}% [{}]", taskId, percent, progressInfo);
|
||
```
|
||
|
||
### **2. 添加预计剩余时间**
|
||
```java
|
||
long elapsed = System.currentTimeMillis() - startTime;
|
||
long avgTime = elapsed / (i + 1);
|
||
long remaining = avgTime * (totalSize - i - 1);
|
||
logger.info("预计剩余时间: {} 秒", remaining / 1000);
|
||
```
|
||
|
||
### **3. 添加每秒处理速度**
|
||
```java
|
||
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条更新)
|
||
- [ ] 进度条流畅增长,无卡顿
|
||
- [ ] 中断导入时显示已处理的详细信息
|
||
- [ ] 日志显示每条记录的处理过程
|
||
- [ ] 日志包含:正在处理、处理成功、失败原因
|
||
- [ ] 最终结果统计正确
|
||
|
||
---
|
||
|
||
## ✅ **总结**
|
||
|
||
### **核心改进**
|
||
1. 进度更新频率从100条提高到5条
|
||
2. 中断时正确保存和显示结果
|
||
3. 添加详细的处理日志
|
||
|
||
### **用户体验**
|
||
- ✅ 实时看到导入进度
|
||
- ✅ 知道正在处理什么
|
||
- ✅ 中断时有明确反馈
|
||
- ✅ 日志便于排查问题
|
||
|
||
### **开发调试**
|
||
- ✅ 日志详细便于调试
|
||
- ✅ 可以追踪每条记录
|
||
- ✅ 快速定位性能瓶颈
|
||
|
||
---
|
||
|
||
**现在重新编译并测试,应该能看到实时的进度更新和详细的处理日志了!** 🚀
|