flowable如何存储流程变量

773 阅读5分钟

引言

用户在发起流程后,如遇到用户任务节点。 即需要用户手动完成审批操作。 这时就会出现一个需求。如何将流程变量存储。 以方便用户在审批时拿到相应数据。
很多人第一想法就是将数据存表。但是该如何考虑将不同的表单(各种不同类型的数据)进行存储呢?

流程变量是什么?

举个例子: 假设我们有一个流程。

WX20230423-220849@2x.png 这是一个请假流程,那么谁请假、请几天、起始时间、请假理由等等,这些都需要说明,不然领导审批的依据是啥?
那么如何传递这些数据,我们就需要流程变量。

@Test

void test01() {

    Map<String, Object> variables = new HashMap<>();

    variables.put("days", 10);

    variables.put("reason", "休息一下");

    variables.put("startTime", new Date());

    ProcessInstance pi = runtimeService.startProcessInstanceByKey("demo01", variables);

    logger.info("id:{},activityId:{}", pi.getId(), pi.getActivityId());
}

流程变量如何存储

流程实例在挂起后,如何保存持有的流程变量。主要就是act_ru_variable。

WX20230423-221755@2x.png

select * from act_ru_variable where PROC_INST_ID_ = "03895336-3efe-11ed-9968-c689ce830b50";

WX20230423-222034@2x.png

流程变量类型

流程实例可以持有变量,称作流程变量(process variables)。
为了使用效率,Flowable将变量分为两种:运行时变量、历史变量。

运行时变量

流程实例运行时的变量,存入act_ru_variable表中。在流程实例运行结束时,此实例的变量在表中删除。

在流程实例创建及启动时,可设置流程变量。所有的startProcessInstanceXXX方法都有一个可选参数用于设置变量。例如,在RuntimeService中:

ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables);

也可以在流程执行中加入变量。例如,(RuntimeService):

    void setVariable(String executionId, String variableName, Object value);
    void setVariableLocal(String executionId, String variableName, Object value);
    void setVariables(String executionId, Map<String, ? extends Object> variables);
    void setVariablesLocal(String executionId, Map<String, ? extends Object> variables);

读取变量方法(请注意TaskService中有类似的方法。这意味着任务与执行一样,可以持有局部变量,其生存期为任务持续的时间。)

    Map<String, Object> getVariables(String executionId);
    Map<String, Object> getVariablesLocal(String executionId);
    Map<String, Object> getVariables(String executionId, Collection<String> variableNames);
    Map<String, Object> getVariablesLocal(String executionId, Collection<String> variableNames);
    Object getVariable(String executionId, String variableName);
    <T> T getVariable(String executionId, String variableName, Class<T> variableClass);

注意:由于流程实例结束时,对应在运行时表的数据跟着被删除。所以,查询一个已经完结流程实例的变量,只能在历史变量表中查找。

全局变量

在整个流程执行期间,这个流程变量都是有效的。

@Test
void test01() {
    Map<String, Object> variables = new HashMap<>();
    variables.put("days", 10);
    variables.put("reason", "休息一下");
    variables.put("startTime", new Date());
    ProcessInstance pi = runtimeService.startProcessInstanceByKey("demo01", variables);
    logger.info("id:{},activityId:{}", pi.getId(), pi.getActivityId());
}

我们可以在启动的时候为流程设置变量,小伙伴们注意到,流程变量的 value 也可以是一个对象
(不过这个对象要能够序列化,即实现了 Serializable 接口),然后在启动的时候传入这个变量即可。

我们在流程启动日志中搜索 休息一下 四个字,可以找到和流程变量相关的 SQL,一共有两条,如下:

insert into ACT_HI_VARINST (ID_, PROC_INST_ID_, EXECUTION_ID_, TASK_ID_, NAME_, REV_, VAR_TYPE_, SCOPE_ID_, SUB_SCOPE_ID_, SCOPE_TYPE_, BYTEARRAY_ID_, DOUBLE_, LONG_ , TEXT_, TEXT2_, CREATE_TIME_, LAST_UPDATED_TIME_) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) , ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) , ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
INSERT INTO ACT_RU_VARIABLE (ID_, REV_, TYPE_, NAME_, PROC_INST_ID_, EXECUTION_ID_, TASK_ID_, SCOPE_ID_, SUB_SCOPE_ID_, SCOPE_TYPE_, BYTEARRAY_ID_, DOUBLE_, LONG_ , TEXT_, TEXT2_) VALUES ( ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) , ( ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) , ( ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )

从标名称上大概就能看出来,ACT_HI_VARINST 是存储流程执行的历史信息的,ACT_RU_VARIABLE 则是保存流程运行时候的信息的。

WX20230423-222034@2x.png

临时变量

个只针对流程中某一个具体的 Task(任务)有效,这个任务执行完毕后,这个流程变量就失效了。

  • 启动一个流程
@Test
void test01() {
    ProcessInstance pi = runtimeService.startProcessInstanceByKey("demo01");
    logger.info("id:{},activityId:{}", pi.getId(), pi.getActivityId());
}
  • 设置本地变量
@Test
void test03() {
    Task task = taskService.createTaskQuery().singleResult();
    taskService.setVariable(task.getId(), "days", 10);
    Map<String, Object> variables = new HashMap<>();
    variables.put("reason", "休息一下");
    variables.put("startTime", new Date());
    taskService.setVariables(task.getId(),variables);
}
  • 执行情况
    查询到某一个 Task,然后设置流程变量,上面这段代码和小伙伴们演示了两种设置方式:
  • 逐个设置
  • 直接设置一个 Map

上面这个设置流程变量的方式,本质上还是往 ACT_HI_VARINST 和 ACT_RU_VARIABLE 表中插入数据。具体的 SQL 也和前面的一样,我就不贴出来了。

本地变量

顾名思义就是临时的,这个不会存入到数据库中。

假设我们启动流程之后,通过 Task 来设置一个本地流程变量,方式如下:

@Test
void test03() {
    Task task = taskService.createTaskQuery().singleResult();
    taskService.setVariableLocal(task.getId(), "days", 10);
    Map<String, Object> variables = new HashMap<>();
    variables.put("reason", "休息一下");
    variables.put("startTime", new Date());
    taskService.setVariables(task.getId(),variables);
}

上面这段代码中,我设置了一个本地变量,两个全局变量,设置完成后,我们去 ACT_RU_VARIABLE 表中来查看一下具体的效果。

1460000042772902.png

大家看到,由于 days 是本地变量,所以它的 TASK_ID_ 有值,这个好理解,说明 days 这个变量和这个具体的 Task 是有关的。

此时如果我们完成这个 Task,代码如下:

@Test
void test06() {
    Task task = taskService.createTaskQuery().singleResult();
    taskService.complete(task.getId());
}

执行查询ACT_RU_VARIABLE, 我们发现本地变量 days 已经没有了.

历史变量

历史变量,存入act_hi_varinst表中。在流程启动时,流程变量会同时存入历史变量表中;在流程结束时,历史表中的变量仍然存在。可理解为“永久代”的流程变量。
获取已完成的、id为’XXX’的流程实例中,所有的HistoricVariableInstances(历史变量实例),并以变量名排序。

    historyService.createHistoricVariableInstanceQuery()
      .processInstanceId("XXX")
      .orderByVariableName.desc()
      .list();