|
@@ -3,6 +3,7 @@
|
|
|
*/
|
|
*/
|
|
|
package com.jeeplus.flowable.service;
|
|
package com.jeeplus.flowable.service;
|
|
|
|
|
|
|
|
|
|
+import com.jeeplus.flowable.mapper.FlowArchiveMapper;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.flowable.engine.impl.persistence.entity.HistoricActivityInstanceEntityImpl;
|
|
import org.flowable.engine.impl.persistence.entity.HistoricActivityInstanceEntityImpl;
|
|
|
import org.flowable.engine.history.HistoricActivityInstance;
|
|
import org.flowable.engine.history.HistoricActivityInstance;
|
|
@@ -30,6 +31,9 @@ public class FlowArchiveService {
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private JdbcTemplate jdbcTemplate;
|
|
private JdbcTemplate jdbcTemplate;
|
|
|
|
|
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FlowArchiveMapper flowArchiveMapper;
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 从归档表查询活动实例列表
|
|
* 从归档表查询活动实例列表
|
|
|
*/
|
|
*/
|
|
@@ -98,6 +102,98 @@ public class FlowArchiveService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
|
|
+ * 执行流程历史数据归档迁移(通过 MyBatis Mapper 实现)
|
|
|
|
|
+ * 将3个月前已结束的流程数据从热表迁移到冷表(归档表)
|
|
|
|
|
+ * SQL 写在 XML 文件中,不使用 @Transactional 让每条 SQL 自动提交
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return 迁移统计信息
|
|
|
|
|
+ */
|
|
|
|
|
+ public Map<String, Object> executeArchive() {
|
|
|
|
|
+ log.info("===== 开始执行流程数据归档迁移 =====");
|
|
|
|
|
+ Map<String, Object> result = new LinkedHashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ // 设置截止日期为3个月前(增量迁移)
|
|
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
|
|
+ cal.add(Calendar.MONTH, -3);
|
|
|
|
|
+ Date cutoffDate = cal.getTime();
|
|
|
|
|
+ String cutoffStr = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cutoffDate);
|
|
|
|
|
+ log.info("迁移截止日期: {}", cutoffStr);
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 检查是否有需要归档的数据
|
|
|
|
|
+ Integer pendingCount = flowArchiveMapper.countPendingArchive(cutoffDate);
|
|
|
|
|
+ if (pendingCount == null || pendingCount == 0) {
|
|
|
|
|
+ log.info("没有需要归档的数据");
|
|
|
|
|
+ result.put("status", "SUCCESS");
|
|
|
|
|
+ result.put("msg", "没有需要归档的数据");
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("待归档流程实例数: {}", pendingCount);
|
|
|
|
|
+
|
|
|
|
|
+ int totalProcinst = 0;
|
|
|
|
|
+ int batchSize = 500;
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 分批迁移流程实例(每次500条)
|
|
|
|
|
+ log.info("开始迁移 act_hi_procinst...");
|
|
|
|
|
+ while (true) {
|
|
|
|
|
+ int inserted = flowArchiveMapper.insertProcinstArchive(cutoffDate, batchSize);
|
|
|
|
|
+ totalProcinst += inserted;
|
|
|
|
|
+ log.info("act_hi_procinst 本批迁移 {} 条, 累计 {} 条", inserted, totalProcinst);
|
|
|
|
|
+ if (inserted < batchSize) break;
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("act_hi_procinst 迁移完成, 共 {} 条", totalProcinst);
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 迁移关联数据
|
|
|
|
|
+ log.info("开始迁移 act_hi_actinst...");
|
|
|
|
|
+ int actinst = flowArchiveMapper.insertActinstArchive();
|
|
|
|
|
+ log.info("act_hi_actinst 迁移完成, 共 {} 条", actinst);
|
|
|
|
|
+
|
|
|
|
|
+ log.info("开始迁移 act_hi_varinst...");
|
|
|
|
|
+ int varinst = flowArchiveMapper.insertVarinstArchive();
|
|
|
|
|
+ log.info("act_hi_varinst 迁移完成, 共 {} 条", varinst);
|
|
|
|
|
+
|
|
|
|
|
+ log.info("开始迁移 act_hi_taskinst...");
|
|
|
|
|
+ int taskinst = flowArchiveMapper.insertTaskinstArchive();
|
|
|
|
|
+ log.info("act_hi_taskinst 迁移完成, 共 {} 条", taskinst);
|
|
|
|
|
+
|
|
|
|
|
+ log.info("开始迁移 act_hi_identitylink...");
|
|
|
|
|
+ int identitylink = flowArchiveMapper.insertIdentitylinkArchive();
|
|
|
|
|
+ log.info("act_hi_identitylink 迁移完成, 共 {} 条", identitylink);
|
|
|
|
|
+
|
|
|
|
|
+ log.info("开始迁移 act_hi_comment...");
|
|
|
|
|
+ int comment = flowArchiveMapper.insertCommentArchive();
|
|
|
|
|
+ log.info("act_hi_comment 迁移完成, 共 {} 条", comment);
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 从热表删除已归档的数据(先删子表,再删主表)
|
|
|
|
|
+ log.info("开始清理热表数据...");
|
|
|
|
|
+ flowArchiveMapper.deleteActinst();
|
|
|
|
|
+ flowArchiveMapper.deleteVarinst();
|
|
|
|
|
+ flowArchiveMapper.deleteTaskinst();
|
|
|
|
|
+ flowArchiveMapper.deleteIdentitylink();
|
|
|
|
|
+ flowArchiveMapper.deleteComment();
|
|
|
|
|
+ flowArchiveMapper.deleteProcinst();
|
|
|
|
|
+ log.info("热表数据清理完成");
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 记录归档日志
|
|
|
|
|
+ try {
|
|
|
|
|
+ flowArchiveMapper.insertArchiveLog(cutoffDate, totalProcinst, actinst, varinst, taskinst, identitylink, comment);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("记录归档日志失败(flow_archive_log表可能不存在): {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 6. 组装返回结果
|
|
|
|
|
+ result.put("status", "SUCCESS");
|
|
|
|
|
+ result.put("cutoffDate", cutoffStr);
|
|
|
|
|
+ result.put("procinst", totalProcinst);
|
|
|
|
|
+ result.put("actinst", actinst);
|
|
|
|
|
+ result.put("varinst", varinst);
|
|
|
|
|
+ result.put("taskinst", taskinst);
|
|
|
|
|
+ result.put("identitylink", identitylink);
|
|
|
|
|
+ result.put("comment", comment);
|
|
|
|
|
+ log.info("===== 流程数据归档迁移完成, 共迁移 {} 条流程实例 =====", totalProcinst);
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
* HistoricActivityInstance 行映射器
|
|
* HistoricActivityInstance 行映射器
|
|
|
* 将归档表数据映射为 Flowable 的 HistoricActivityInstance 对象
|
|
* 将归档表数据映射为 Flowable 的 HistoricActivityInstance 对象
|
|
|
*/
|
|
*/
|