记录一次生产事故,因为使用的岗位配置人员,在拦截器中该岗位人员为空,所以导致节点没有审核人。因为之前写的接口前端没给加按钮,也因为过于自信对flowable表的熟悉,所以选择了直接插表。最后在用户complete任务直接报错。
### Cause: java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`ACT_RU_IDENTITYLINK`, CONSTRAINT `ACT_FK_TSKASS_TASK` FOREIGN KEY (`TASK_ID_`) REFERENCES `ACT_RU_TASK` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT)
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:199)
at org.apache.ibatis.session.defaults.DefaultSqlSession.delete(DefaultSqlSession.java:212)
at org.flowable.common.engine.impl.db.DbSqlSession.flushDeleteEntities(DbSqlSession.java:636)
at org.flowable.common.engine.impl.db.DbSqlSession.flushDeletes(DbSqlSession.java:593)
at org.flowable.common.engine.impl.db.DbSqlSession.flush(DbSqlSession.java:360)
at org.flowable.common.engine.impl.interceptor.CommandContext.flushSessions(CommandContext.java:192)
at org.flowable.common.engine.impl.interceptor.CommandContext.close(CommandContext.java:61)
at org.flowable.common.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:81)
at org.flowable.common.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:51)
at org.flowable.common.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:35)
at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:56)
at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:51)
at org.flowable.engine.impl.TaskServiceImpl.complete(TaskServiceImpl.java:213)
at com.thwater.service.impl.FlowTaskServiceImpl.completeUserTask(FlowTaskServiceImpl.java:264)
at com.thwater.service.impl.FlowTaskServiceImpl$$FastClassBySpringCGLIB$$657cd805.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
at
最后翻阅错误日志和debug日志,发现没有执行先删除子表的操作,结合此处去翻了下源代码,然后找到了惊喜。
protected static void handleRelatedEntities(CommandContext commandContext, TaskEntity task, String deleteReason, boolean cascade,
boolean fireTaskListener, boolean fireEvents, FlowableEventDispatcher eventDispatcher) {
boolean isTaskRelatedEntityCountEnabled = CountingEntityUtil.isTaskRelatedEntityCountEnabled(task);
if (!isTaskRelatedEntityCountEnabled
|| (isTaskRelatedEntityCountEnabled && ((CountingTaskEntity) task).getSubTaskCount() > 0)) {
TaskService taskService = CommandContextUtil.getTaskService(commandContext);
List<Task> subTasks = taskService.findTasksByParentTaskId(task.getId());
for (Task subTask : subTasks) {
internalDeleteTask((TaskEntity) subTask, deleteReason, cascade, true, fireTaskListener, fireEvents); // Sub tasks are always immediately deleted
}
}
if (!isTaskRelatedEntityCountEnabled
|| (isTaskRelatedEntityCountEnabled && ((CountingTaskEntity) task).getIdentityLinkCount() > 0)) {
boolean deleteIdentityLinks = true;
if (fireEvents) {
List<IdentityLinkEntity> identityLinks = CommandContextUtil.getIdentityLinkService(commandContext).findIdentityLinksByTaskId(task.getId());
for (IdentityLinkEntity identityLinkEntity : identityLinks) {
eventDispatcher.dispatchEvent(FlowableIdentityLinkEventBuilder.createEntityEvent(FlowableEngineEventType.ENTITY_DELETED, identityLinkEntity));
}
deleteIdentityLinks = !identityLinks.isEmpty();
}
if (deleteIdentityLinks) {
CommandContextUtil.getIdentityLinkService(commandContext).deleteIdentityLinksByTaskId(task.getId());
}
}
if (!isTaskRelatedEntityCountEnabled
|| (isTaskRelatedEntityCountEnabled && ((CountingTaskEntity) task).getVariableCount() > 0)) {
Map<String, VariableInstanceEntity> taskVariables = task.getVariableInstanceEntities();
ArrayList<VariableByteArrayRef> variableByteArrayRefs = new ArrayList<>();
for (VariableInstanceEntity variableInstanceEntity : taskVariables.values()) {
if (fireEvents) {
eventDispatcher.dispatchEvent(FlowableVariableEventBuilder.createEntityEvent(FlowableEngineEventType.ENTITY_DELETED, variableInstanceEntity));
}
if (variableInstanceEntity.getByteArrayRef() != null && variableInstanceEntity.getByteArrayRef().getId() != null) {
variableByteArrayRefs.add(variableInstanceEntity.getByteArrayRef());
}
}
for (VariableByteArrayRef variableByteArrayRef : variableByteArrayRefs) {
CommandContextUtil.getByteArrayEntityManager(commandContext).deleteByteArrayById(variableByteArrayRef.getId());
}
if (!taskVariables.isEmpty()) {
CommandContextUtil.getVariableService(commandContext).deleteVariablesByTaskId(task.getId());
}
}
}
总结下:**能用官方api尽量使用官方api,**除非你觉得你足够实力去直接操作表,否则绝对不要像我一样。因为我们这里就我自己在搞工作流,大家都是能少干就少干,毕竟干的多错的多,更何况这个东西以前都没接触过。有的时候想想,挺有意思,机缘巧合接触了工作流,不知道怎么的就感觉爱上了它,不断地在犯错中成长,一次又一次的因为工作流被批评,也丝毫没有想过放弃。一年的时间,一个人把公司的工作流项目重构几个版本,如今看着它成长的可以应对公司各种奇葩需求,心中不禁一丝欣慰。但是今天发布新的kpi考核指标,不再允许我去优化我的心血,毕竟我也要生活。也未尝不是好事,可以去写写文章,分享自己的经验,把自己的想法用在开源项目上。