引言
Activiti 7 工作流引擎使用约 25 张核心数据库表来存储流程定义、运行时状态、历史记录和身份数据等信息。这些表名统一以 ACT_ 打头,后跟两个字母标识表的用途,每类表对应 Activiti 提供的不同服务 API。例如,ACT_RE_ 前缀表示 Repository(仓库)数据,用于保存流程定义等静态信息;ACT_RU_ 前缀表示 Runtime(运行时)数据,用于保存流程实例执行过程中的动态数据;ACT_ID_ 前缀表示 Identity(身份)数据,用于保存用户与用户组等身份信息;ACT_HI_ 前缀表示 History(历史)数据,用于保存已完成的流程实例、任务等历史记录;ACT_GE_ 前缀表示 General(通用)数据,用于存储各种通用用途的数据。Activiti 在流程运行时只向运行时表写入数据,在流程结束时即清除相应的运行时记录,以保证运行时表始终精简、查询高效。
下面我们按类别介绍 Activiti 7 的核心表结构,包括每张表的用途,以及它们在流程启动、任务分配、任务完成与流程结束等典型生命周期阶段如何被使用和更新。此外,还重点说明了这些表之间的关联关系,以帮助理解 Activiti 底层实现。
核心数据库表及作用
Repository 类表(流程仓库,ACT_RE_*)
Repository 类的表保存流程的静态信息,例如流程定义及部署。主要包括:
- ACT_RE_DEPLOYMENT:流程部署信息表。每次通过 RepositoryService 部署流程定义时,都会在此表新增一条记录,记录部署的 ID、名称、部署时间等信息。一个部署可以包含一个或多个流程定义及相关资源。
- ACT_RE_PROCDEF:流程定义表。存储所有已部署的流程定义的基本信息,如流程定义的 KEY、名称、版本号、所属部署以及流程 BPMN 资源名称等。当流程定义被挂起或激活时,此表的对应记录会更新相关状态属性。
- ACT_RE_MODEL:流程模型表。用于存储在流程设计器中创建的流程模型(未部署的流程定义)。Activiti Modeler 等设计工具保存的模型以 JSON 或 XML 形式存放在此表中,包含模型的名称、标识以及版本等。模型内容通常以二进制形式存于通用资源表(ACT_GE_BYTEARRAY)中,由 ACT_RE_MODEL 表引用。当模型被正式部署为流程定义后,会在 ACT_RE_PROCDEF 表生成对应的流程定义记录。
Repository 类表之间存在关联:ACT_RE_DEPLOYMENT 与 ACT_RE_PROCDEF 通过部署 ID 关联(一个部署可包含多个流程定义),流程定义记录包含部署 ID 字段引用其所属的部署;同时,ACT_RE_PROCDEF 的资源名称字段可用于在 ACT_GE_BYTEARRAY 表中查找对应的流程定义 XML 或流程图资源。
Runtime 类表(运行时数据,ACT_RU_*)
Runtime 类的表在流程实例执行过程中存储动态运行数据,当流程实例结束时,这些表中的相应记录会被删除。主要的运行时表包括:
- ACT_RU_EXECUTION:执行实例表。存储流程实例以及流程执行的路径(Execution)信息。每启动一个流程实例,会在此表产生一条对应的执行记录(根执行对象,代表流程实例本身),其 ID 即为流程实例 ID。同时,对于流程中并行或子流程等结构,Activiti 也会在此表创建额外的执行记录来表示不同的执行路径。每条执行记录包含当前活动节点 ID、所属流程定义 ID、父执行 ID(若存在父子执行关系)、业务键等状态数据。执行表是流程实例的核心,运行时引擎通过操作此表来推进流程状态。当流程进入下一个节点时,相关执行记录的当前活动 ID 会更新;若进入子流程或并行分支,则会新增子执行记录。
- ACT_RU_TASK:运行时任务表。存储当前处于未完成状态的用户任务,每个运行中流程实例的每个待办任务对应此表的一条记录。任务记录包含任务 ID、名称、创建时间、到期时间、优先级、任务所属的执行实例和流程实例 ID,以及任务的受理人(ASSIGNEE_)等信息。当任务被创建、签收、完成时,此表将插入或更新记录,并在任务完成时删除记录。开发者常用 TaskService 查询或修改该表的数据,例如认领任务会更新 ASSIGNEE_ 字段。
- ACT_RU_VARIABLE:运行时变量表。保存流程实例或任务范围内的流程变量当前值。每当设置流程变量时,都会在此表插入或更新一条记录,包括变量名称、类型、当前值,以及关联的执行实例 ID、流程实例 ID;若是任务本地变量,还会有任务 ID。变量值如果是大对象(如长字符串、文件等),则不会直接保存在此表中,而是以二进制形式存入 ACT_GE_BYTEARRAY 表,并在 ACT_RU_VARIABLE 中通过 BYTEARRAY_ID_ 引用。流程实例结束时,与之关联的变量记录会删除,必要时其值会被转存到历史表中。
- ACT_RU_IDENTITYLINK:运行时身份关联表。用于关联任务或流程实例与相应的用户或用户组。当任务存在候选人、候选组,或已有指派的受理人时,都会在此表存储对应关系。例如,一个任务指定了候选组,则会有一条记录表示"某用户组是该任务的候选";任务被某用户认领后,也会在此表添加记录表示"该用户是任务的办理人"。此外,如果配置流程启动者身份,流程实例与启动用户的关系也会在此表存储。此表包含任务 ID、流程实例 ID、用户 ID、组 ID 以及关联类型(如参与者、候选人、负责人等),方便查询任务相关的所有参与者或某用户相关的任务。任务完成后,其对应的 IdentityLink 记录也会被移除。
- ACT_RU_JOB:异步作业表。Activiti 使用 Job 概念来处理异步任务、定时器等后台作业事件。该表保存当前等待执行或重试的作业,如异步的服务任务、定时启动事件等。表中记录包括作业类型(定时器、异步等)、关联的执行实例、下次执行时间(对于定时器)、重试次数及异常堆栈等信息。引擎在流程定义包含异步节点或定时边界事件时会往此表插入记录,由 Job Executor 定期查表执行到期作业。作业执行成功后,记录即从此表删除;如果多次重试仍失败,则会被标记为挂起或死信。
- ACT_RU_EVENT_SUBSCR:事件订阅表。存储流程实例中等待触发的事件信息,包括事件类型(如消息、信号、定时器事件等)和事件名称,以及关联的执行实例 ID、流程实例 ID 等。流程在等待外部消息或信号时,会在此表登记一条订阅记录,便于引擎查询哪些流程实例在等待特定事件;当事件发生时,引擎根据订阅记录恢复流程执行,并删除该订阅记录。
此外,还有一些扩展的运行时表(如用于子流程父子关系的 ACT_RU_ENTITYLINK)可能会在特定场景下启用。上述 Runtime 表之间通过主键和外键或引用形成关联,例如 ACT_RU_TASK、ACT_RU_VARIABLE 等都包含 PROC_INST_ID_(流程实例 ID)和 EXECUTION_ID_ 来关联所属的执行实例;ACT_RU_TASK 的 EXECUTION_ID_ 指向 ACT_RU_EXECUTION 表中的记录,ACT_RU_IDENTITYLINK 也可通过 TASK_ID_ 或 PROC_INST_ID_ 关联到对应任务或流程实例,从而便于根据执行实例查找当前任务、变量,或根据任务找到相关的执行路径和参与者。
History 类表(历史数据,ACT_HI_*)
History 历史表用于存放已完成或正在进行中的流程实例的历史信息。Activiti 会将运行时数据复制或迁移到历史表中,以便提供审计和查询报告,同时不影响运行时性能。历史表以 HI 前缀开头,名称往往与对应的运行时表相对应。主要历史表包括:
- ACT_HI_PROCINST:历史流程实例表。每个启动的流程实例在此表对应一条记录。从流程实例启动时就插入记录,记录中包含开始时间,而流程结束后会更新结束时间、持续时长等,同时还存储发起人、业务键、流程定义 ID、实例是否完成等信息。
- ACT_HI_ACTINST:历史活动实例表。记录流程实例中执行过的每个活动节点,例如开始事件、任务节点、网关、结束事件等,每经过一次活动便产生一条记录,字段包括所属流程实例 ID、节点 ID、节点名称、开始时间、结束时间、持续时间、执行人等。
- ACT_HI_TASKINST:历史任务实例表。记录每一个用户任务的执行情况。当任务创建时会插入历史记录,记录任务的开始时间、任务名称、办理人等;任务完成时更新结束时间、持续时长、办理结果等。即使任务数据在运行时表中已被删除,历史记录仍然保留。
- ACT_HI_VARINST:历史变量实例表。保存流程执行过程中流程变量的最终状态或关键变更。如果启用了较高的历史记录级别,还会记录变量的每次变化情况。一般情况下,该表只记录变量的最终值,而中间变更会存于历史明细表中。
- ACT_HI_DETAIL:历史明细表。当历史级别设置为"full"时,会记录流程运行中的详细信息,如每个任务完成时的表单字段提交值、每个流程变量每次更新的具体值,以及任务评论等细粒度日志。表结构通常包括所属流程实例、任务、执行 ID、变量名、变量值(或引用二进制数据)等。
- ACT_HI_COMMENT:历史评论表。用于记录对任务或流程实例添加的批注或评论,字段包括所属任务或流程实例、用户 ID、评论内容、时间等。
- ACT_HI_ATTACHMENT:历史附件表。用于记录流程实例或任务相关的附件信息。附件的元数据(如名称、类型、上传时间及关联任务或流程实例)存于此表,而附件的二进制内容存储在 ACT_GE_BYTEARRAY 表中,并通过 BYTEARRAY_ID_ 进行引用。
历史表与运行时表之间通常通过流程实例 ID 或任务 ID 进行关联。例如,ACT_HI_TASKINST 的 ID 与运行时任务 ID 通常相同,以便关联查询;ACT_HI_ACTINST 可以通过 TASK_ID_ 或 EXECUTION_ID_ 找到对应的记录。流程结束时,运行时表中的记录被删除,而历史表中的记录则更新补全,确保完整地保留了整个流程的操作轨迹。
Identity 类表(身份数据,ACT_ID_*)
Identity 类表存储 Activiti 内置的用户、组及其关系等身份信息。主要包括:
- ACT_ID_USER:用户表。保存用户帐号信息,如用户 ID、姓名、邮箱、密码哈希值、盐值等。默认情况下,Activiti 使用此表中的数据进行任务的受理人或候选人验证。该表的 PICTURE_ID_ 字段可选地关联到 ACT_GE_BYTEARRAY 表,用于存储用户头像等二进制数据。
- ACT_ID_GROUP:用户组表。保存用户组或角色的信息,在流程定义中用于指定候选组。
- ACT_ID_MEMBERSHIP:用户-组关联表。用于实现用户与用户组之间的多对多关系。每条记录表示某用户属于某一用户组,通常以组合键(USER_ID_ + GROUP_ID_)唯一标识。
- ACT_ID_INFO:用户扩展信息表。用于存储用户的附加属性,例如电话号码、地址或第三方帐号 ID 等信息。这些附加属性以键值对形式保存在该表中,部分数据可能通过 BYTEARRAY_ID_ 引用二进制数据。
在 Activiti 内部,身份表既可以直接使用,也支持通过 LDAP 等外部系统管理用户;如果未集成外部身份服务,则任务的认领和候选人检查均基于上述表的数据。
General 通用表(ACT_GE_*)
General 类表用于存储引擎各模块通用的数据,例如:
- ACT_GE_PROPERTY:属性表。存储引擎的全局属性数据,如数据库 schema 版本等信息,以及早期版本中用于生成唯一 ID 的计数器。
- ACT_GE_BYTEARRAY:二进制数据表。用于存储流程引擎运行中产生的各种二进制大对象(BLOB),如部署的 BPMN XML 文件、流程图图片、表单文件、流程变量中的大字段数据等。部署流程时,流程的 XML 文本和图片会分别以字节数组形式存入该表,并关联到对应部署的 ID。对于运行时大字段变量(例如超过 4000 字符的字符串或文件附件),Activiti 会将其序列化后存入此表,并在变量表中通过 BYTEARRAY_ID_ 引用。
General 表在整个流程生命周期中主要起到支撑作用,例如 ACT_GE_BYTEARRAY 在部署阶段存储流程定义的 XML 文件,在流程运行过程中也可能存储表单附件或变量序列化值;而 ACT_GE_PROPERTY 则在引擎启动或升级时用于读取或更新元数据信息。它们并不直接与单个流程实例生命周期挂钩,而是被引擎全局使用。
流程生命周期各阶段的表使用情况
了解各张表的静态作用后,我们来看一个流程实例从启动到结束的生命周期中,这些表如何被操作和关联。
流程启动阶段
- 读取流程定义
引擎首先从 Repository 表中读取要启动的流程定义信息,例如通过流程定义 key 查找最新发布的版本,并据此载入流程模型(必要时从 ACT_GE_BYTEARRAY 提取 BPMN XML)。 - 创建执行实例
引擎在 ACT_RU_EXECUTION 表中插入一条新记录,表示流程实例的启动,这条记录的 ID 就是流程实例 ID,同时记录流程定义 ID、启动时间等信息。对于初始执行对象,它也代表整个流程实例的根执行。 - 记录流程历史(开始)
如果启用了历史记录,此时会在 ACT_HI_PROCINST 表中插入对应流程实例的历史记录,记录流程实例 ID、流程定义 ID、启动时间等;结束时间暂时为空,以便后续更新。 - 创建首个任务和执行路径
根据流程定义,若第一个步骤为用户任务,引擎会在 ACT_RU_TASK 表中创建任务记录,并在 ACT_RU_IDENTITYLINK 表中记录任务参与者信息(如候选人或候选组)。同时,在 ACT_HI_TASKINST 表中插入任务的历史记录。如果起始节点不是用户任务(如自动执行的服务任务),则引擎会连续执行,直到遇到需要等待的节点。 - 创建初始变量
如果启动流程时传入了流程变量,Activiti 会在 ACT_RU_VARIABLE 表中为每个变量插入记录,并关联到新建的执行 ID。根据历史级别的配置,初始变量也可能在历史表中留下记录。 - 事件订阅初始化
流程启动后,如果存在等待事件(例如消息开始事件或中间捕获事件),引擎会在 ACT_RU_EVENT_SUBSCR 表中登记相应的订阅记录,以便后续事件触发时能及时恢复流程执行。
任务分配阶段
"任务分配"是指将一个用户任务指派给具体办理人或候选人,通常有两种方式:
- 预先指定受理人或候选人
如果流程定义中已指定办理人(assignee)或候选人(candidate users/groups),那么任务创建时,ACT_RU_TASK 表的 ASSIGNEE_ 字段会直接填入指定的用户,或者在 ACT_RU_IDENTITYLINK 表中插入对应的候选记录,此时任务已分配或候选可见,无需额外操作。 - 运行时认领任务(Claim)
如果任务未直接指定办理人,则需要候选人通过 TaskService.claim 进行认领。认领操作会将 ACT_RU_TASK 表中该任务的 ASSIGNEE_ 字段更新为认领人的用户 ID,同时更新 ACT_RU_IDENTITYLINK 表中任务的身份关联,移除之前的候选记录,并新增表明当前办理人的记录。
无论是哪种方式,运行时表和历史表都会反映任务分配的变化,例如 ACT_RU_TASK 中的 ASSIGNEE_ 字段以及 ACT_HI_TASKINST 中的办理人记录会相应更新;若任务办理人发生变更(例如转办或委派),相关数据也会同步更新。
任务完成阶段
当用户完成任务(调用 TaskService.complete)时,Activiti 会执行以下操作:
- 更新并删除运行时任务
在 ACT_RU_TASK 表中找到该任务记录,记录任务完成时间后将其删除;同时,与任务关联的运行时身份链接记录(在 ACT_RU_IDENTITYLINK 中)也会一并删除。 - 写入任务历史
完成任务后,历史任务表(ACT_HI_TASKINST)中对应的记录会更新结束时间、持续时长等信息,同时如果有任务表单字段或输出变量,也会记录到历史明细表中。 - 流程变量处理
若任务完成时提交了本地变量或修改了流程变量,ACT_RU_VARIABLE 表中的相应记录会更新或删除,同时历史表中也会记录相应的变化。 - 推进流程实例状态
完成任务后,引擎会操作 ACT_RU_EXECUTION 表,更新当前执行记录的活动节点。如果下一个节点是用户任务,则会创建新的任务记录;若为并行网关、子流程或结束事件,则相应地调整执行记录,直至流程结束。 - 事件订阅处理
若任务完成触发了某些事件,引擎也会在 ACT_RU_EVENT_SUBSCR 表中增删订阅记录或触发等待的流程实例继续执行。
流程结束阶段
当流程实例到达终止节点(正常结束或强制终止)时,Activiti 会进行如下收尾处理:
- 清理运行时数据
删除该流程实例所有相关的运行时记录,包括 ACT_RU_EXECUTION 中的根执行及所有子执行、ACT_RU_TASK 中的所有未完成任务、ACT_RU_VARIABLE 中的变量记录、ACT_RU_EVENT_SUBSCR 中的事件订阅、以及 ACT_RU_JOB 中的定时器或异步作业记录等。这样确保运行时表只保留活跃流程实例的数据,保持高性能。 - 更新历史数据
在历史表中标记流程实例的结束,例如在 ACT_HI_PROCINST 表中更新结束时间及持续时长;ACT_HI_ACTINST 表中最后一个活动记录也会更新为结束状态。历史数据得以完整保留,便于后续查询和审计。 - 结束流程实例的关系
结束时,还会处理与流程实例相关的其它关系数据,例如在 ACT_HI_TASKINST 表中标记所有任务已结束,或删除不再需要的身份关联记录等。
总体来说,流程结束阶段的表操作可概括为"清理运行时,完备历史"。运行时相关的记录全部删除,而历史表完整保留了流程从启动到结束的所有信息,既保证系统高效运行,也为审计和追踪提供了依据。
表与表之间的逻辑关联
从上述内容可以看出,Activiti 各数据库表之间存在紧密的逻辑关联:
- 流程定义与部署资源
流程定义表(ACT_RE_PROCDEF)记录了流程的元数据,而实际的 BPMN XML 文件和流程图等则以二进制形式存储在 ByteArray 表中,通过部署 ID 及资源名称进行关联。 - 流程实例执行与任务
执行表(ACT_RU_EXECUTION)为核心,任务表(ACT_RU_TASK)通过 EXECUTION_ID_ 外键引用执行记录,每个任务同时记录所属的流程实例 ID,便于按流程实例快速查询任务。 - 执行、任务与流程变量
变量表中的 PROC_INST_ID_ 和 EXECUTION_ID_ 将变量关联到具体的流程实例或执行节点;若变量为任务本地变量,还会有 TASK_ID_ 指向所属任务,确保能够区分全局变量与局部变量,并在任务完成时正确清理变量记录。 - 任务与身份关联
任务的身份关联表(ACT_RU_IDENTITYLINK)保存了任务与用户/组之间的对应关系,其字段中的 USER_ID_ 和 GROUP_ID_ 与身份表(ACT_ID_USER、ACT_ID_GROUP)中的主键对应。尽管数据库层未强制外键约束,但逻辑上它们实现了候选人、受理人等功能。 - 运行时表与历史表
历史表基本上是对运行时表的归档。ACT_HI_PROCINST 对应流程实例,ACT_HI_TASKINST 对应任务,ACT_HI_ACTINST 对应活动节点,ACT_HI_VARINST 对应流程变量等。通过流程实例 ID 等字段,历史表与运行时表"平行"关联,使得即使运行时记录删除后,仍可通过历史表查询到完整信息。 - ByteArray 与其它表
作为通用二进制存储,ACT_GE_BYTEARRAY 与多张表产生关联引用,例如流程定义中的流程图、历史附件、以及大字段变量的存储等。因此,在删除 ByteArray 表中的数据时需要谨慎,确保没有其它表继续引用。
这些关联关系确保了 Activiti 在不同阶段通过多张表协同完成数据持久化:流程实例启动时,多表联动插入数据;任务分配时,运行时和身份关联表共同更新;任务完成或流程结束时,运行时记录被清理,而历史记录则得到完整保留,从而实现了高效运行与完整留痕的平衡。
结语
Activiti 7 的 25 张核心数据库表共同构成了流程引擎的持久化层,各自分工明确:Repository 表定义流程的静态蓝图,Runtime 表记录流程运行时的动态数据,History 表保留流程执行的完整历史记录,Identity 表管理参与流程的用户和用户组信息,而 General 表则支撑着各种通用数据存储。在一个流程实例的生命周期中,这些表协同工作:流程启动时在运行时表登记新生数据,任务执行中不断更新关联信息,流程结束时及时清理运行时数据并完善历史记录,既保证了系统的高效运行,也为后续的查询审计提供了依据。
理解这些表的作用和它们之间的关联,对于掌握 Activiti 底层实现原理、进行高级应用(如自定义查询、数据库迁移、数据清理)都具有非常大的帮助。希望这篇整理后的文章能让你对 Activiti 的数据库设计有更深入的认识!