ACT_RU_IDENTITYLINK表直接加候选人的坑

文章讲述了在使用Flowable工作流引擎时,由于直接插入数据库引发的生产事故。由于接口和岗位配置问题,导致任务没有审核人,进而尝试手动插表,结果违反了数据库外键约束。作者在排查错误日志后,发现应使用官方API处理相关实体,而非直接操作表。文章强调了使用API的重要性,并分享了从错误中学习和成长的经验。
摘要由CSDN通过智能技术生成

记录一次生产事故,因为使用的岗位配置人员,在拦截器中该岗位人员为空,所以导致节点没有审核人。因为之前写的接口前端没给加按钮,也因为过于自信对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考核指标,不再允许我去优化我的心血,毕竟我也要生活。也未尝不是好事,可以去写写文章,分享自己的经验,把自己的想法用在开源项目上。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值