| | |
| | | |
| | | 1. 修改实体类文件中的字段定义 |
| | | 2. 修改对应的SQL文件中的表结构定义 |
| | | 3. 执行SQL语句更新数据库表结构 |
| | | 3. 执行SQL语句更新数据库表结构 |
| | | |
| | | ## 性能优化 |
| | | |
| | | 系统在处理大量数据时可能会遇到内存占用过高的问题,特别是在执行以下操作时: |
| | | |
| | | 1. 采购订单数据同步(`syncPurchaseOrderDetails`方法) |
| | | 2. 送货单数据处理 |
| | | |
| | | ### 已实施的优化措施 |
| | | |
| | | 1. **分批处理数据**:将大量数据分成小批次进行处理,减少一次性内存占用 |
| | | 2. **及时释放对象引用**:处理完毕后将不再使用的对象引用设为null,帮助GC回收内存 |
| | | 3. **优化SQL查询**:避免一次性加载大量数据到内存 |
| | | |
| | | ### JVM调优建议 |
| | | |
| | | 在启动应用时,可以通过以下JVM参数优化内存使用: |
| | | |
| | | ```bash |
| | | java -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar XkyCollection.jar |
| | | ``` |
| | | |
| | | 参数说明: |
| | | |
| | | - `-Xms512m`:初始堆内存大小为512MB |
| | | - `-Xmx1024m`:最大堆内存大小为1024MB(根据服务器实际可用内存调整) |
| | | - `-XX:MetaspaceSize=128m`:初始元空间大小为128MB |
| | | - `-XX:MaxMetaspaceSize=256m`:最大元空间大小为256MB |
| | | - `-XX:+UseG1GC`:使用G1垃圾收集器,适合大内存应用 |
| | | - `-XX:MaxGCPauseMillis=200`:最大GC暂停时间目标为200毫秒 |
| | | |
| | | ### 监控建议 |
| | | |
| | | 1. 使用JConsole或VisualVM等工具监控应用内存使用情况 |
| | | 2. 关注GC日志,分析内存使用模式 |
| | | 3. 在生产环境中,可以添加以下参数开启GC日志: |
| | | ``` |
| | | -Xloggc:/path/to/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps |
| | | ``` |
| | | |
| | | ## 常见问题排查 |
| | | |
| | | ### 内存溢出(OutOfMemoryError) |
| | | |
| | | 如果遇到内存溢出问题: |
| | | |
| | | 1. 检查是否有大量数据一次性加载到内存 |
| | | 2. 确认是否有内存泄漏(对象创建后未被释放) |
| | | 3. 增加JVM堆内存大小 |
| | | 4. 考虑使用分页查询或流式处理大数据量 |
| | | |
| | | ### 服务卡顿 |
| | | |
| | | 如果服务出现卡顿: |
| | | |
| | | 1. 检查是否有长时间运行的事务 |
| | | 2. 确认数据库连接是否正常释放 |
| | | 3. 查看GC日志,确认是否频繁发生Full GC |
| | | 4. 优化数据库查询,添加适当的索引 |
| | | |
| | | ## 最佳实践 |
| | | |
| | | 1. 避免在高峰期执行大量数据同步操作 |
| | | 2. 对于定时任务,选择在系统负载较低的时段执行 |
| | | 3. 使用适当的批处理大小(建议100-500条记录) |
| | | 4. 定期清理不再需要的历史数据 |
| | | |
| | | ## 异步任务处理 |
| | | |
| | | 系统使用异步任务处理机制来执行耗时操作,避免阻塞主线程和定时任务调度线程。主要包括以下几个部分: |
| | | |
| | | ### 线程池配置 |
| | | |
| | | 系统配置了两个专用线程池: |
| | | |
| | | 1. **采购订单同步线程池 (purchaseTaskExecutor)** |
| | | - 核心线程数:1(确保同一时间只有一个采购同步任务在执行) |
| | | - 最大线程数:2 |
| | | - 队列容量:5 |
| | | - 拒绝策略:CallerRunsPolicy(调用者线程执行) |
| | | |
| | | 2. **通用异步任务线程池 (taskExecutor)** |
| | | - 核心线程数:5 |
| | | - 最大线程数:10 |
| | | - 队列容量:25 |
| | | - 拒绝策略:CallerRunsPolicy(调用者线程执行) |
| | | |
| | | ### 定时任务优化 |
| | | |
| | | 所有定时任务都使用异步执行方式,防止互相阻塞: |
| | | |
| | | 1. **采购订单同步任务**:每天12:05执行一次,使用专用线程池 |
| | | 2. **设备实时数据获取**:每5分钟执行一次,使用通用线程池 |
| | | 3. **补偿逻辑**:每5分钟执行多次,使用通用线程池 |
| | | 4. **钉钉数据同步**:每53分钟执行一次,使用通用线程池 |
| | | |
| | | ### 任务执行状态管理 |
| | | |
| | | 使用 AtomicBoolean 标记任务执行状态,避免同一任务重复执行: |
| | | |
| | | ```java |
| | | private final AtomicBoolean isRunning = new AtomicBoolean(false); |
| | | |
| | | // 任务开始前检查 |
| | | if(!isRunning. |
| | | |
| | | compareAndSet(false,true)){ |
| | | log. |
| | | |
| | | info("上一次任务还在执行中,跳过本次执行"); |
| | | return; |
| | | } |
| | | |
| | | // 任务结束后重置状态 |
| | | finally{ |
| | | isRunning. |
| | | |
| | | set(false); |
| | | } |
| | | ``` |
| | | |
| | | ### 异步任务执行流程 |
| | | |
| | | 1. 定时器触发任务 |
| | | 2. 检查任务是否已在运行,如已运行则跳过 |
| | | 3. 将任务提交到相应的线程池异步执行 |
| | | 4. 定时器立即返回,不等待任务完成 |
| | | 5. 任务在线程池中执行完毕后重置状态标记 |
| | | |
| | | 这种机制确保了即使某个任务执行时间较长,也不会影响其他定时任务的正常执行。 |
| | | |
| | | ## 最新优化更新 |
| | | |
| | | 在最近的优化中,我们进一步改进了系统性能和稳定性: |
| | | |
| | | 1. **送货单数据处理优化** |
| | | - 实现了 XkyService.GetSaveDetail() 方法的分批处理 |
| | | - 每批处理10条送货单数据,减少内存占用 |
| | | - 增强了异常处理,单条数据异常不会影响整批处理 |
| | | |
| | | 2. **异步任务处理增强** |
| | | - 为 DeliveryNoticeService 添加了 @Async 注解的异步处理方法 |
| | | - 实现了 processAsyncBatch 方法,支持并行处理多批数据 |
| | | - 优化了日志记录,便于问题排查 |
| | | |
| | | 3. **错误处理改进** |
| | | - 所有关键方法都添加了详细的日志记录 |
| | | - 实现了更细粒度的异常捕获和处理 |
| | | - 防止单个任务失败导致整个流程中断 |
| | | |
| | | ### 异步执行流程示例 |
| | | |
| | | 以下是一个典型的异步执行流程: |
| | | |
| | | ``` |
| | | 主线程: 开始处理100条数据 |
| | | 主线程: 将数据分为5批,每批20条 |
| | | 主线程: 提交批次1到异步线程池 |
| | | 主线程: 提交批次2到异步线程池 |
| | | 主线程: 提交批次3到异步线程池 |
| | | 主线程: 提交批次4到异步线程池 |
| | | 主线程: 提交批次5到异步线程池 |
| | | 主线程: 全部数据处理提交完成 |
| | | 异步线程1: 开始处理批次1 |
| | | 异步线程2: 开始处理批次2 |
| | | 异步线程3: 开始处理批次3 |
| | | 异步线程1: 批次1处理完成 |
| | | 异步线程1: 开始处理批次4 |
| | | 异步线程2: 批次2处理完成 |
| | | 异步线程2: 开始处理批次5 |
| | | 异步线程3: 批次3处理完成 |
| | | 异步线程1: 批次4处理完成 |
| | | 异步线程2: 批次5处理完成 |
| | | ``` |
| | | |
| | | 这种方式确保了主线程不会被长时间阻塞,同时充分利用了系统资源进行并行处理。 |