# GPS分段里程计算任务超时问题修复说明 ## 问题描述 GPS分段里程计算定时任务执行时出现数据库连接超时错误: ``` ERROR c.r.q.t.VehicleGpsSegmentMileageTask - GPS分段里程计算任务执行失败 java.lang.RuntimeException: 批量计算失败: ### Error querying database. Cause: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure The last packet successfully received from the server was 60,022 milliseconds ago. ``` ## 问题原因 1. **数据库Socket超时配置过短**:`socketTimeout: 60000`(60秒),对于大数据量GPS查询处理不足 2. **查询性能不佳**:缺少必要的数据库索引,导致大表扫描耗时过长 3. **错误处理不完善**:单个车辆计算失败会影响整个批处理流程 4. **缺少进度日志**:无法了解批量处理的实时进度 ## 解决方案 ### 1. 增加数据库连接超时时间 **修改文件**: - `ruoyi-admin/src/main/resources/application-dev.yml` - `ruoyi-admin/src/main/resources/application-test.yml` - `ruoyi-admin/src/main/resources/application-prod.yml` **修改内容**: ```yaml # 配置网络超时时间(从60秒增加到5分钟) socketTimeout: 300000 ``` **原因**:GPS分段里程计算需要处理大量数据,60秒的超时时间不足以完成查询操作。增加到5分钟(300秒)可以避免正常查询被误判为超时。 ### 2. 优化数据库索引 **执行SQL文件**:`sql/optimize_gps_query_performance.sql` **关键索引**: ```sql -- 组合索引:vehicle_id + collect_time ALTER TABLE tb_vehicle_gps ADD INDEX idx_vehicle_collect_time (vehicle_id, collect_time); -- 单列索引:collect_time ALTER TABLE tb_vehicle_gps ADD INDEX idx_collect_time (collect_time); -- tb_vehicle_gps_calculated表索引 ALTER TABLE tb_vehicle_gps_calculated ADD INDEX idx_gps_id (gps_id); ADD INDEX idx_vehicle_id (vehicle_id); ``` **效果**: - 大幅提升按车辆ID和时间范围查询的性能 - 优化活跃车辆查询速度 - 改善LEFT JOIN查询性能 ### 3. 增强批处理错误处理 **修改文件**:`VehicleGpsSegmentMileageServiceImpl.java` **改进点**: 1. **单车失败不影响全局**:单个车辆计算失败不会中断整个批处理 2. **详细的进度日志**:每处理10辆车输出一次进度 3. **成功/失败统计**:记录成功和失败的车辆数量 4. **更详细的错误信息**:包含堆栈跟踪,便于问题定位 **代码改进**: ```java int successCount = 0; int failedCount = 0; for (int i = 0; i < vehicleIds.size(); i++) { try { // 处理单个车辆 int segmentCount = calculateVehicleSegmentMileage(vehicleId, startTime, endTime); if (segmentCount > 0) { successCount++; } } catch (Exception e) { failedCount++; logger.error("计算车辆失败,但继续处理下一辆", e); // 不中断批处理 } // 进度日志 if ((i + 1) % 10 == 0) { logger.info("进度: {}/{}, 成功: {}, 失败: {}", ...); } } ``` ## 部署步骤 ### 1. 数据库优化(必须) ```bash # 连接到MySQL数据库 mysql -u root -p # 执行索引优化SQL source sql/optimize_gps_query_performance.sql # 验证索引创建成功 SHOW INDEX FROM tb_vehicle_gps; SHOW INDEX FROM tb_vehicle_gps_calculated; ``` ### 2. 应用配置更新(必须) 1. 备份当前配置文件 2. 更新配置文件中的`socketTimeout`参数 3. 重启应用服务 ```bash # 停止服务 ./ry.sh stop # 启动服务 ./ry.sh start # 查看日志 tail -f logs/sys-info.log ``` ### 3. 验证修复效果 1. **手动触发定时任务**: - 登录后台管理系统 - 进入【系统监控】->【定时任务】 - 找到"GPS分段里程实时计算"任务 - 点击【执行一次】按钮 2. **查看执行日志**: ```bash # 查看GPS计算日志 grep "VehicleGpsSegmentMileageTask" logs/sys-info.log # 查看成功/失败统计 grep "批量分段里程计算完成" logs/sys-info.log ``` 3. **检查数据库**: ```sql -- 查看最新的分段里程记录 SELECT * FROM tb_vehicle_gps_segment_mileage ORDER BY create_time DESC LIMIT 10; -- 统计今日处理的车辆数 SELECT COUNT(DISTINCT vehicle_id) as vehicle_count FROM tb_vehicle_gps_segment_mileage WHERE DATE(create_time) = CURDATE(); ``` ## 性能监控建议 ### 1. 定时任务执行时间监控 在定时任务管理中查看执行时长: - 正常情况:每5分钟执行一次,处理10分钟数据,应在1-2分钟内完成 - 异常情况:超过3分钟需要关注,可能存在性能问题 ### 2. 数据库慢查询日志 检查MySQL慢查询日志: ```sql -- 查看慢查询配置 SHOW VARIABLES LIKE 'slow_query%'; SHOW VARIABLES LIKE 'long_query_time'; -- 启用慢查询日志(如果未启用) SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 2; ``` ### 3. Druid监控 访问Druid监控页面:`http://your-domain/druid/` - 用户名:ruoyi - 密码:123456 关注指标: - SQL执行时间 - 连接池使用情况 - 慢SQL列表 ## 后续优化建议 ### 1. 定期清理历史数据 GPS数据量大,建议定期清理历史数据: ```sql -- 保留最近90天的GPS原始数据 DELETE FROM tb_vehicle_gps WHERE collect_time < DATE_SUB(NOW(), INTERVAL 90 DAY); -- 优化表空间 OPTIMIZE TABLE tb_vehicle_gps; ``` 可以创建定时任务每月执行一次。 ### 2. 分批处理大量车辆 如果车辆数量超过1000辆,建议修改批处理逻辑,分批处理: ```java // 每批处理100辆车辆 int batchSize = 100; for (int i = 0; i < vehicleIds.size(); i += batchSize) { List batchIds = vehicleIds.subList(i, Math.min(i + batchSize, vehicleIds.size())); processBatch(batchIds); } ``` ### 3. 使用异步处理 对于特别耗时的操作,可以考虑使用异步处理: ```java @Async public CompletableFuture calculateVehicleAsync(Long vehicleId) { // 异步计算 } ``` ### 4. 增加缓存机制 对于频繁查询的车辆信息,可以使用Redis缓存: ```java @Cacheable(value = "vehicleInfo", key = "#vehicleId") public VehicleInfo getVehicleInfo(Long vehicleId) { return vehicleInfoMapper.selectVehicleInfoById(vehicleId); } ``` ## 相关文件清单 ### 修改的文件 1. `ruoyi-admin/src/main/resources/application-dev.yml` - 开发环境配置 2. `ruoyi-admin/src/main/resources/application-test.yml` - 测试环境配置 3. `ruoyi-admin/src/main/resources/application-prod.yml` - 生产环境配置 4. `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsSegmentMileageServiceImpl.java` - 批处理逻辑优化 5. `ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml` - 添加SQL注释 ### 新增的文件 1. `sql/optimize_gps_query_performance.sql` - 数据库性能优化SQL ## 故障排查 ### 问题1:执行SQL时报错"索引已存在" **解决方案**: ```sql -- 删除已存在的索引 DROP INDEX idx_vehicle_collect_time ON tb_vehicle_gps; DROP INDEX idx_collect_time ON tb_vehicle_gps; -- 重新创建索引 -- 然后执行optimize_gps_query_performance.sql ``` ### 问题2:修改配置后仍然超时 **检查步骤**: 1. 确认配置文件修改生效:检查当前激活的profile(dev/test/prod) 2. 确认应用已重启:`ps -ef | grep java` 3. 查看Druid连接池配置:访问 `/druid/` 检查socketTimeout值 4. 检查数据库服务器配置:`SHOW VARIABLES LIKE 'wait_timeout';` ### 问题3:索引创建后性能未改善 **检查步骤**: ```sql -- 1. 验证索引是否被使用 EXPLAIN SELECT DISTINCT vehicle_id FROM tb_vehicle_gps WHERE collect_time >= DATE_SUB(NOW(), INTERVAL 7 DAY); -- 2. 更新表统计信息 ANALYZE TABLE tb_vehicle_gps; -- 3. 检查表数据量 SELECT COUNT(*) FROM tb_vehicle_gps; ``` ## 总结 本次修复主要解决了GPS分段里程计算任务的超时问题,通过以下措施: 1. ✅ 增加数据库连接超时时间(60秒 -> 300秒) 2. ✅ 添加数据库索引优化查询性能 3. ✅ 改进批处理错误处理机制 4. ✅ 增强日志输出,便于监控和问题定位 **预期效果**: - 任务执行不再超时 - 查询性能提升50%以上 - 单个车辆失败不影响整体处理 - 实时了解处理进度 **注意事项**: - 必须执行数据库索引优化SQL - 必须重启应用使配置生效 - 建议定期清理历史GPS数据 - 持续监控任务执行情况