乐趣区

关于activiti:SpringBoot-Activiti6系列教程七变量

接上一篇文章,咱们探索了 execution 的运行机制,activiti 里变量的作用域就是通过 execution 实现,activiti 里变量按作用域有以下几种

  • 执行变量(variable)
  • 本地变量(LocalVariable)
  • 长期变量(TransVariable)

执行变量作用域在 execution 上,本地变量作用域在 task 上,长期变量不存储数据库,流程进入期待节点(比方 UserTask)变量主动革除。

须要应用变量的是 RuntimeServiceTaskService,本文次要对这两个 service 中变量的应用做具体阐明,防止在不理解变量应用范畴的状况下,谬误的应用变量,导致流程出错。

变量表构造

变量存储在表 ACT_RU_VARIABLE 上,

mysql> describe ACT_RU_VARIABLE;
+---------------+---------------+------+-----+---------+-------+
| Field         | Type          | Null | Key | Default | Extra |
+---------------+---------------+------+-----+---------+-------+
| ID_           | varchar(64)   | NO   | PRI | NULL    |       |
| REV_          | int(11)       | YES  |     | NULL    |       |
| TYPE_         | varchar(255)  | NO   |     | NULL    |       |
| NAME_         | varchar(255)  | NO   |     | NULL    |       |
| EXECUTION_ID_ | varchar(64)   | YES  | MUL | NULL    |       |
| PROC_INST_ID_ | varchar(64)   | YES  | MUL | NULL    |       |
| TASK_ID_      | varchar(64)   | YES  | MUL | NULL    |       |
| BYTEARRAY_ID_ | varchar(64)   | YES  | MUL | NULL    |       |
| DOUBLE_       | double        | YES  |     | NULL    |       |
| LONG_         | bigint(20)    | YES  |     | NULL    |       |
| TEXT_         | varchar(4000) | YES  |     | NULL    |       |
| TEXT2_        | varchar(4000) | YES  |     | NULL    |       |
+---------------+---------------+------+-----+---------+-------+
12 rows in set (0.00 sec)

NAME_是变量名称,TYPE_是变量类型,依据 TYPE_ 类型会将数据保留到不同的字段里,如 TYPE_为 string 则保留到 TEXT_ 或者 TEXT_2 中,如果是二进制数据,数据存储到表 ACT_GE_BYTEARRAY 中,并将 id 存储到 BYTEARRAY_ID_ 字段上。EXECUTION_ID_、PROC_INST_ID_、TASK_ID_控制变量的作用域,如果 TASK_ID_为 null 则为执行变量,如果不为 null 则为本地变量。

TaskService 变量

TaskService有两个设置变量相干的 API(理论有四个,但另外两个性能相似),定义如下:

/**
 * set variable on a task. If the variable is not already existing, it will be created in the most outer scope. This means the process instance in case this task is related to an execution.
 */
void setVariable(String taskId, String variableName, Object value);


/**
 * set variable on a task. If the variable is not already existing, it will be created in the task.
 */
void setVariableLocal(String taskId, String variableName, Object value);

setVariable 设置的是全局变量,也就是 instance 的变量,设置完后流程全局可见,setVariableLocal 设置的是本地变量,设置完后只有该 task 可见。

执行如下示例代码:

taskService.setVariable(task.getId(), "variable", "this is Variable");
taskService.setVariableLocal(task.getId(), "localVariable", "this is Local Variable");
mysql> select * from activiti.ACT_RU_VARIABLE t where t.proc_inst_id_=100001 and name_='variable' or name_='localVariable'\G;
*************************** 1. row ***************************
          ID_: 100024
         REV_: 1
        TYPE_: string
        NAME_: variable
EXECUTION_ID_: 100001
PROC_INST_ID_: 100001
     TASK_ID_: NULL
BYTEARRAY_ID_: NULL
      DOUBLE_: NULL
        LONG_: NULL
        TEXT_: this is Variable
       TEXT2_: NULL
*************************** 2. row ***************************
          ID_: 100025
         REV_: 1
        TYPE_: string
        NAME_: localVariable
EXECUTION_ID_: 100008
PROC_INST_ID_: 100001
     TASK_ID_: 100015
BYTEARRAY_ID_: NULL
      DOUBLE_: NULL
        LONG_: NULL
        TEXT_: this is Local Variable
       TEXT2_: NULL
2 rows in set (0.00 sec)

variable变量 EXECUTION_ID_和 PROC_INST_ID_都是 100001,100001 是流程的实例 id(instance_id),阐明该变量作用域在整个 instance 上,整个流程周期内都能够应用,localVariable设置了 TASK_ID,并且设置了所在的 EXECUTION_ID_,阐明只能在指定的 Task 上应用。

既然有设置变量,那必定有获取变量,能够先试着想想上面几行代码的输入会是什么?

System.out.println("getVariable(variable) ==>"+taskService.getVariable(taskId,"variable"));
System.out.println("getVariable(localVariable) ==>"+taskService.getVariable(taskId,"localVariable"));
System.out.println("getVariableLocal(variable) ==>"+taskService.getVariableLocal(taskId,"variable"));
System.out.println("getVariableLocal(localVariable) ==>"+taskService.getVariableLocal(taskId,"localVariable"));

输入的后果如下:

getVariable(variable) ==>this is Variable
getVariable(localVariable) ==>this is Local Variable
getVariableLocal(variable) ==>null
getVariableLocal(localVariable) ==>this is Local Variable

通过 getVariable 既可能获取到执行变量,也能获取到本地变量,通过 getVariableLocal 只能获取到本地变量。至于为什么 Local 的变量用 getVariable 能获取到,咱们能够看下 getVariable 执行的 sql 过程


#1. 尝试用名称和 taskid 进行查问(即查问本地变量)==>  Preparing: select * from ACT_RU_VARIABLE where TASK_ID_ = ? and NAME_= ? 
==> Parameters: 100015(String), variable(String)
<==      Total: 0

#2. 如果没有查问到尝试查问执行变量(指定 TASK_ID_为 NULL,设置 EXECUTION_ID_和 NAME_)==>  Preparing: select * from ACT_RU_EXECUTION where ID_ = ? 
==> Parameters: 100008(String)
<==      Total: 1

==>  Preparing: select * from ACT_RU_VARIABLE where EXECUTION_ID_ = ? and NAME_= ? and TASK_ID_ is null 
==> Parameters: 100008(String), variable(String)
<==      Total: 0


#3. 如果没有查问到尝试查问以后 EXECUTION 的父 EXECUTION 的变量,直至顶级 EXECUTION,也就是 instance 了
==>  Preparing: select * from ACT_RU_EXECUTION where ID_ = ? 
==> Parameters: 100003(String)
<==      Total: 1

==>  Preparing: select * from ACT_RU_VARIABLE where EXECUTION_ID_ = ? and NAME_= ? and TASK_ID_ is null 
==> Parameters: 100003(String), variable(String)
<==      Total: 0

==>  Preparing: select * from ACT_RU_EXECUTION where ID_ = ? 
==> Parameters: 100001(String)
<==      Total: 1

==>  Preparing: select * from ACT_RU_VARIABLE where EXECUTION_ID_ = ? and NAME_= ? and TASK_ID_ is null 
==> Parameters: 100001(String), variable(String)
<==      Total: 1

getVariable 会尝试从本地变量到执行变量到实例变量层层往上找,直到找到为止。getVariableLocal 的执行过程如下:

==>  Preparing: select * from ACT_RU_VARIABLE where TASK_ID_ = ? and NAME_= ? 
==> Parameters: 100015(String), variable(String)
<==      Total: 1

getVariableLocal 间接依据 TASK_ID_和 NAME_进行查找,如果没找到就没找到,不会持续往上执行。

基于以上后果,咱们能够得出如下论断

  • TaskService.getVariable 能够获取该 EXECUTION 链上的任意变量
  • TaskService.getVariableLocal 只能获取本地变量,也就是定义在 TASK 的变量
  • TaskService.getVariable 因为存在递归调用,性能没有 getVariableLocal 好,所以在流程里应该优先思考应用本地变量

RuntimeService 变量

流程发动

流程发动时传入的变量,保留到流程实例里在整个流程流转周期内都能够拜访到,上面是一个带参数的流程发动代码示例:

public String start() {Map<String, Object> params = new HashMap<>();
    params.put("startVariable", "this is startVariable");
    ProcessInstance instance = runtimeService.startProcessInstanceByKey("myProcess1", params);
    return instance.getId();}

存储到数据库中的变量如下

mysql> select * from activiti.ACT_RU_VARIABLE t where t.proc_inst_id_=100001 and name_='startVariable'\G;
*************************** 1. row ***************************
          ID_: 100002
         REV_: 1
        TYPE_: string
        NAME_: startVariable
EXECUTION_ID_: 100001
PROC_INST_ID_: 100001
     TASK_ID_: NULL
BYTEARRAY_ID_: NULL
      DOUBLE_: NULL
        LONG_: NULL
        TEXT_: this is startVariable
       TEXT2_: NULL
1 row in set (0.00 sec)

EXECUTION_ID_PROC_INST_ID_ 都是 100001,而100001 正是流程的 instanceid,因而该变量是保留到 instance 中,流程的任意节点都应用到,依据上面对 getVariable 的剖析咱们晓得,activiti 会逐级往上寻找变量,而 instance 位于最顶级,因而流程内所有的节点都能够应用。

Execution 变量

同样,咱们能够通过示例代码察看 activiti 设置在 Execution 上的状况。

runtimeService.setVariable(task.getExecutionId(), "runtimeVariable", "this is runtimeVariable");
runtimeService.setVariableLocal(task.getExecutionId(), "runtimeLocalVariable", "this is Local runtimeLocalVariable");
System.out.println("getVariable(variable) ==>"+runtimeService.getVariable(task.getExecutionId(),"runtimeVariable"));
System.out.println("getVariable(localVariable) ==>"+runtimeService.getVariable(task.getExecutionId(),"runtimeLocalVariable"));
System.out.println("getVariableLocal(variable) ==>"+runtimeService.getVariableLocal(task.getExecutionId(),"runtimeVariable"));
System.out.println("getVariableLocal(localVariable) ==>"+runtimeService.getVariableLocal(task.getExecutionId(),"runtimeLocalVariable"));

输入为:

getVariable(variable) ==>this is runtimeVariable
getVariable(localVariable) ==>this is Local runtimeLocalVariable
getVariableLocal(variable) ==>null
getVariableLocal(localVariable) ==>this is Local runtimeLocalVariable

getVariable 数据库执行过程

# 基于以后 EXECUTION,依据 EXECUTION_ID_和 NAME_进行查问,并且非本地变量(TASK_ID_ is null)==>  Preparing: select * from ACT_RU_EXECUTION where ID_ = ? 
==> Parameters: 100009(String)
<==      Total: 1
==>  Preparing: select * from ACT_RU_VARIABLE where EXECUTION_ID_ = ? and NAME_= ? and TASK_ID_ is null 
==> Parameters: 100009(String), runtimeVariable(String)
<==      Total: 0

#依据父 EXECUTION 进行查问
==>  Preparing: select * from ACT_RU_EXECUTION where ID_ = ? 
==> Parameters: 100003(String)
<==      Total: 1
==>  Preparing: select * from ACT_RU_VARIABLE where EXECUTION_ID_ = ? and NAME_= ? and TASK_ID_ is null 
==> Parameters: 100003(String), runtimeVariable(String)
<==      Total: 0

#持续往上查问
==>  Preparing: select * from ACT_RU_EXECUTION where ID_ = ? 
==> Parameters: 100001(String)
<==      Total: 1
==>  Preparing: select * from ACT_RU_VARIABLE where EXECUTION_ID_ = ? and NAME_= ? and TASK_ID_ is null 
==> Parameters: 100001(String), runtimeVariable(String)
<==      Total: 1

getVariableLocal 数据库执行过程

# 基于以后 EXECUTION,依据 EXECUTION_ID_和 NAME_进行查问,并且非本地变量(TASK_ID_ is null)==>  Preparing: select * from ACT_RU_VARIABLE where EXECUTION_ID_ = ? and NAME_= ? and TASK_ID_ is null 
==> Parameters: 100009(String), runtimeVariable(String)
<==      Total: 0

基于以上后果,能够得悉,RuntimeService.getVariable 基于以后 EXECUTION 所在的 EXECUTION 链进行一级级往上找,直到找到符合条件的变量,getVariableLocal 只找以后 EXECUTION 的变量,过程根本和 TaskService.getVariable 以及 TaskService.getVariableLocal 相似

长期变量

长期变量不做长久化存储,也就是不存储数据库,TaskService 和 RuntimeService 都能够设置长期变量,设置长期变量 api 如下:

void setTransientVariable(String variableName, Object variableValue);
void setTransientVariableLocal(String variableName, Object variableValue);
void setTransientVariables(Map<String, Object> transientVariables);
void setTransientVariablesLocal(Map<String, Object> transientVariables);

Object getTransientVariable(String variableName);
Object getTransientVariableLocal(String variableName);

Map<String, Object> getTransientVariables();
Map<String, Object> getTransientVariablesLocal();

获取长期变量也能够通过 getVariable 获取,实际上 getVariable 首先从长期变量中读取,读不到才进行数据库查问,因而如果长期变量和执行变量或者本地变量名称一样的话,实际上读取到的是长期变量。

长期变量因为是存储在内存中的,因而当流程流到期待状态 (wait state) 的节点,如 UserTask 节点,长期变量就生效,基于这个个性,能够将长期变量作为 Service 两头后果的保留。

退出移动版