业务系统通常用订单号、申请单号识别一笔业务,而工作流引擎的许多操作使用流程实例 ID。两边可以通过 businessKey 关联:先按业务标识找到实例,再取得 processInstanceId。
这里最容易踩的坑是查询入口。运行时查询面向仍在运行的实例;流程结束后,要到历史记录中查,而不是把运行时的空结果当成“从未发起”。
查询仍在运行的实例
以下片段使用 Activiti 7.1.0.M6 引擎层的 RuntimeService,假设服务已注入,businessKey 来自当前用户有权访问的业务单据:
List<org.activiti.engine.runtime.ProcessInstance> running =
runtimeService.createProcessInstanceQuery()
.processInstanceBusinessKey(businessKey)
.list();
for (org.activiti.engine.runtime.ProcessInstance instance : running) {
String processInstanceId = instance.getId();
// 根据业务选择需要操作的实例,而不是默认取第一条。
}
这里用 list() 而不是直接用 singleResult(),是因为查询条件不一定唯一。若系统有多个流程定义、租户或重新发起的记录,需要继续增加相应约束;只有业务上保证结果至多一条,才适合使用单结果查询。对应版本 RuntimeService
查询已结束的实例
历史服务可以按同样的业务标识检索,再用 finished() 限制已结束的记录:
List<org.activiti.engine.history.HistoricProcessInstance> finished =
historyService.createHistoricProcessInstanceQuery()
.processInstanceBusinessKey(businessKey)
.finished()
.list();
如果需要一个包含进行中和已结束记录的查询页面,可以不加 finished(),但前提是相应历史数据确实被记录且尚未清理。历史查询不是独立于历史级别和保留策略的永久索引。历史实例查询接口
为什么仍应保存实例关联
“业务单据是哪一笔”和“这一次流程执行是哪一轮”是两个问题。一张申请单如果被驳回后重新发起,可能对应多个实例。仅保存业务单号,后续就需要重新推导用户到底想查看哪一轮。
比较清楚的关联方式是由业务端保存业务单号、流程定义标识、流程实例 ID、发起轮次,以及必要的租户信息。业务单号便于查询和对账,实例 ID 则准确指向某次执行;两者不需要互相替代。
查到历史,不等于还能做运行时操作
历史查询可以用于展示流程经过和结果,但不能让已结束实例重新变成运行中的实例。挂起、恢复等操作之前,应重新检查实例状态、操作权限和当前业务规则。
同样,拿不到记录也可能是历史已清理、租户条件错误或关联值写错。排查时先核对发起时写入的 businessKey 和对应实例 ID,再判断是否需要查询历史,避免为了“查到一条”而取消必要的数据权限条件。