千家信息网

java中如何避免集合死链调用

发表于:2024-11-27 作者:千家信息网编辑
千家信息网最后更新 2024年11月27日,这篇文章给大家分享的是有关java中如何避免集合死链调用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1. 前言 开发过程中, 一些集合 的变动会触发任务去 改变 其他的集
千家信息网最后更新 2024年11月27日java中如何避免集合死链调用

这篇文章给大家分享的是有关java中如何避免集合死链调用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

1. 前言

 开发过程中, 一些集合 的变动会触发任务去 改变 其他的集合 ,为了保障任务的正确执行,应避免出现死循环调用,即对 集合之间的影响关系 进行一些限制。怕日后遗忘,特在此记录。

2. 场景

  • A 集合影响 A 集合。

  • A 集合影响 B 集合,B 集合影响了 A 集合。

  • A 集合影响 B 集合,B 集合影响了 C 集合,C 集合影响了 A 集合。

  • A 集合影响 B 集合、C 集合,B 集合影响了 D 集合,C 集合影响了 E 集合,E 集合影响 A 集合。

3. 环境

3.1 开发环境准备

  • JDK 1.8

  • SpringBoot 2.x

  • Mysql 8

  • redis

3.2 数据准备

3.2.1 Mysql数据库表及数据

dp_process表

CREATE TABLE `dp_process` (  `ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID',  `NAME` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '名称',  `CODE` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '代码',  `CATEGORY` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '类型 1=楼宇,2=房地产',  `IN_COLS` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '输入集合',  `OUT_COLS` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '影响集合',  `REMARK` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',  `ENABLED` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '是否开启',  `STATUS` int DEFAULT NULL COMMENT '状态 数据状态:0=正常,1=删除,失效',  `CREATED_BY` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',  `CREATED_TIME` datetime DEFAULT NULL COMMENT '创建时间',  `UPDATED_BY` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',  `UPDATED_TIME` datetime DEFAULT NULL COMMENT '更新时间',  `REVISION` int DEFAULT '0' COMMENT '乐观锁',  PRIMARY KEY (`ID`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='数据处理 ';

dp_process 表中的数据

INSERT INTO `gccs`.`dp_process`(`ID`, `NAME`, `CODE`, `CATEGORY`, `IN_COLS`, `OUT_COLS`, `REMARK`, `ENABLED`, `STATUS`, `CREATED_BY`, `CREATED_TIME`, `UPDATED_BY`, `UPDATED_TIME`, `REVISION`) VALUES ('1', 'B', 'B', 'ly', 'A', 'B', 'B', '1', 0, NULL, NULL, NULL, NULL, 0);INSERT INTO `gccs`.`dp_process`(`ID`, `NAME`, `CODE`, `CATEGORY`, `IN_COLS`, `OUT_COLS`, `REMARK`, `ENABLED`, `STATUS`, `CREATED_BY`, `CREATED_TIME`, `UPDATED_BY`, `UPDATED_TIME`, `REVISION`) VALUES ('2', 'D', 'D', 'ly', 'B', 'D', 'D', '1', 0, NULL, NULL, NULL, NULL, 0);INSERT INTO `gccs`.`dp_process`(`ID`, `NAME`, `CODE`, `CATEGORY`, `IN_COLS`, `OUT_COLS`, `REMARK`, `ENABLED`, `STATUS`, `CREATED_BY`, `CREATED_TIME`, `UPDATED_BY`, `UPDATED_TIME`, `REVISION`) VALUES ('3', 'E', 'E', 'ly', 'B', 'E', 'E', '1', 0, NULL, NULL, NULL, NULL, 0);INSERT INTO `gccs`.`dp_process`(`ID`, `NAME`, `CODE`, `CATEGORY`, `IN_COLS`, `OUT_COLS`, `REMARK`, `ENABLED`, `STATUS`, `CREATED_BY`, `CREATED_TIME`, `UPDATED_BY`, `UPDATED_TIME`, `REVISION`) VALUES ('4', 'G', 'G', 'ly', 'D', 'G', 'G', '1', 0, NULL, NULL, NULL, NULL, 0);INSERT INTO `gccs`.`dp_process`(`ID`, `NAME`, `CODE`, `CATEGORY`, `IN_COLS`, `OUT_COLS`, `REMARK`, `ENABLED`, `STATUS`, `CREATED_BY`, `CREATED_TIME`, `UPDATED_BY`, `UPDATED_TIME`, `REVISION`) VALUES ('5', 'F', 'F', 'ly', 'D', 'F', 'F', '1', 0, NULL, NULL, NULL, NULL, 0);
3.2.2 redis库数据
keyValue
A[{ "id": "1","outCols": "B"}]
B[{"id": "2","outCols": "D"},{"id": "3","outCols": "E"}]
D[{"id": "4","outCols": "G"},{"id": "5","outCols": "F"}]

4. 解决方式

通过递归的方式循环查询、对比。

本例主要牵扯到的知识点有:

  • Stack (栈,先进后出)

  • 递归

  • redis简单增删操作

本文以 修改方法 代码为例,介绍如何实现防死链调用,非常简单。

/**     * @create  2021-07-08 更新 数据处理     * @param dpProcess 数据处理 模型     * @param updateNil 全字段更新(新增时此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}     * @return     */    @Override    public int modify(DpProcess dpProcess, String updateNil){                // **省略一堆代码**        // 输入集合统一处理operInclos(dpProcess, orignDpProcess.getInCols());        // **省略一堆代码**    }

 operInclos() 方法 : 重点 ,主要做了数据校验、redis中数据更新等一系列操作

/**     * @create 输入集合统一处理 2021/7/11 14:13     * @param dpProcess 新数据处理对象     * @param oldClos 原数据处理对象中的输入集合     * @return     */    private void operInclos(DpProcess dpProcess, String oldClos) {        // 新数据处理对象中的输入集合        String inCols = dpProcess.getInCols();        // 若新数据处理对象中的输入集合没有值,则直接跳过,不进行操作        if(StringUtils.isNotBlank(inCols)){            if(dpProcess.getInCols().contains(dpProcess.getOutCols())){                throw new ServiceException("数据处理流程配置输入流程调用了输出集合!");            }            // 数据类型转换            Set set = new HashSet(Arrays.asList(inCols.split(",")));            // 循环遍历输入集合            for (String inClo : set) {                // 最终需要遍历的list                List childFinalList = new ArrayList<>();                // 从redis中获取当前集合的影响关系                String dpProcessJson = (String) redisUtil.get(inClo);                // 如果redis中存储的集合影响关系不为空,做简单的遍历去重处理                if(StringUtils.isNotBlank(dpProcessJson)){                    // redis中存储的集合影响关系列表                    List children = new ArrayList<>();                    // 进行数据类型转换                    children = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);                    for (DpProcessVo dpProcessVo1 : children) {                        if(dpProcess.getId().equals(dpProcessVo1.getId())){                            continue;                        }                        childFinalList.add(dpProcessVo1);                    }                    // 添加本次影响的集合                    DpProcessVo dpProcess1 = new DpProcessVo();                    dpProcess1.setId(dpProcess.getId());                    dpProcess1.setOutCols(dpProcess.getOutCols());                    childFinalList.add(dpProcess1);                }                // 如果redis中没有此输入集合的影响关系,则可以直接进行添加                else{                    DpProcessVo dpProcess1 = new DpProcessVo();                    dpProcess1.setId(dpProcess.getId());                    dpProcess1.setOutCols(dpProcess.getOutCols());                    childFinalList.add(dpProcess1);                }                // 验证数据处理流程配置输入流程是否调用了输出集合                Stack nodeStack = new Stack<>();                // 设置模型                DpProcessVo dpProcessVoTop = new DpProcessVo();                dpProcessVoTop.setOutCols(inClo);                dpProcessVoTop.setId(dpProcess.getId());                nodeStack.add(dpProcessVoTop);                // 遍历需要进行死链校验的数据                for (DpProcessVo dpProcessVo : childFinalList) {                    // 是否添加标识(默认为添加,如果集合为死链,则进行提示)                    boolean addFlag = true;                    // 循环遍历栈                    for (DpProcessVo processVo : nodeStack) {                        if(processVo.getOutCols().equals(dpProcessVo.getOutCols())){                            addFlag = false;                            break;                        }                    }                    if(!addFlag){                        throw new ServiceException("数据处理流程配置输入流程调用了输出集合!");                    }                    // 将dpProcessVo推到这个堆栈的顶部                    nodeStack.push(dpProcessVo);                    // 验证数据处理流程配置输入流程是否调用了输出集合                    invaldClosInfo(nodeStack);                    // 移除此堆栈顶部的对象并将该对象作为此函数的值返回                    nodeStack.pop();                }            }            // 处理需要删除的集合            dealNeedDeleteCols(dpProcess, oldClos, set);            // 获取并设置最终的集合名称            String finallyCols = StringUtils.join(set.toArray(), ",");            dpProcess.setInCols(finallyCols);            // 省略一堆更新redis的操作        }    }

 invaldClosInfo()方法: 递归深度遍历

/**     * @create 验证数据处理流程配置输入流程是否调用了输出集合  2021/7/20 22:10     * @param nodeStack 深度遍历栈     * @return void     */    public void invaldClosInfo(Stack nodeStack) {        // 查看此堆栈顶部的对象而不将其从堆栈中移除        DpProcessVo dpProcessVo = nodeStack.peek();        // 从redis中查找此集合影响的流程关系        String dpProcessJson = (String) redisUtil.get(dpProcessVo.getOutCols());        // 如果集合没有影响其他集合,则直接返回        if(StringUtils.isBlank(dpProcessJson)){            return;        }        //获得节点的子节点,对于二叉树就是获得节点的左子结点和右子节点        List children = new ArrayList<>();        // redis中原来存储的信息        children = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);        // 遍历集合影响的集合关系        for (DpProcessVo dpProcessVo1 : children) {            boolean addFlag = true;            for (DpProcessVo processVo : nodeStack) {                if(processVo.getOutCols().equals(dpProcessVo1.getOutCols())){                    addFlag = false;                    break;                }            }            if(!addFlag){                throw new ServiceException("数据处理流程配置输入流程调用了输出集合!");            }            // 将dpProcessVo推到这个堆栈的顶部            nodeStack.push(dpProcessVo1);            // 验证数据处理流程配置输入流程是否调用了输出集合            invaldClosInfo(nodeStack);            // 移除此堆栈顶部的对象并将该对象作为此函数的值返回            nodeStack.pop();        }    }

5.完整代码

记录代码,方便日后复习、调用、重构。

5.1 Model

 模型主要分两部分:数据处理模型和简化版的数据处理模型。

 DpProcess:数据处理模型,数据完整的Sql操作

import com.alibaba.fastjson.annotation.JSONField;import com.baomidou.mybatisplus.annotation.*;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import lombok.EqualsAndHashCode;import lombok.experimental.Accessors;import java.io.Serializable;import java.util.Date;/** * 

* 数据处理 *

* * @since 2021-07-08 */@Data@EqualsAndHashCode(callSuper = false)@Accessors(chain = true)@ApiModel(value="DpProcess对象", description="数据处理 ")@TableName("dp_process")public class DpProcess implements Serializable { @TableField(exist = false) public static final String ENABLED = "ENABLED"; @TableField(exist = false) public static final String STATUS = "STATUS"; @TableField(exist = false) public static final String CATEGORY = "CATEGORY"; private static final long serialVersionUID = 1L; @ApiModelProperty(value = "ID") @TableId(value = "ID", type = IdType.ASSIGN_ID) private String id; @ApiModelProperty(value = "名称") @TableField("NAME") private String name; @ApiModelProperty(value = "代码") @TableField("CODE") private String code; @ApiModelProperty(value = "类型 1=楼宇,2=房地产") @TableField("CATEGORY") private String category; @ApiModelProperty(value = "输入集合") @TableField("IN_COLS") private String inCols; @ApiModelProperty(value = "影响集合") @TableField("OUT_COLS") private String outCols; @ApiModelProperty(value = "备注") @TableField("REMARK") private String remark; @ApiModelProperty(value = "是否开启 0:否 1:是") @TableField("ENABLED") private String enabled; @ApiModelProperty(value = "状态 数据状态:0=正常,1=删除,失效") @TableField(value = "STATUS", fill = FieldFill.INSERT) private Integer status; @ApiModelProperty(value = "创建人") @TableField(value = "CREATED_BY", fill = FieldFill.INSERT) private String createdBy; @ApiModelProperty(value = "创建时间") @JSONField(format = "yyyy-MM-dd HH:mm:ss") @TableField(value = "CREATED_TIME", fill = FieldFill.INSERT) private Date createdTime; @ApiModelProperty(value = "更新人") @TableField(value = "UPDATED_BY", fill = FieldFill.UPDATE) private String updatedBy; @ApiModelProperty(value = "更新时间") @JSONField(format = "yyyy-MM-dd HH:mm:ss") @TableField(value = "UPDATED_TIME", fill = FieldFill.UPDATE) private Date updatedTime; @ApiModelProperty(value = "乐观锁") @Version @TableField(value = "REVISION", fill = FieldFill.INSERT) private Integer revision;}

DpProcessVo: 数据处理简单模型,处理redis数据结构数据。

import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import lombok.EqualsAndHashCode;import lombok.experimental.Accessors;@Data@EqualsAndHashCode(callSuper = false)@Accessors(chain = true)@ApiModel(value="DpProcessVo对象", description="数据处理简单模型 ")public class DpProcessVo{    @ApiModelProperty(value = "ID")    private String id;    @ApiModelProperty(value = "影响集合")    private String outCols;}

5.2 Controller

updateNil:让用户选择使用那种更新方式,也可以把接口一拆为二,主要看个人习惯。

/**     * @create  2021-07-08 更新 数据处理     * @param dpProcess 数据处理 模型     * @param updateNil 全字段更新(新增时此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}     * @return     */    @ApiOperation(value="更新",notes = "更新")    @PostMapping("/modify")    public Result modify(            @ApiParam(name = "dpProcess", value = "数据处理 模型", required = true) @RequestBody DpProcess dpProcess,            @ApiParam(name = "updateNil", value = "全字段更新(新增时此字段可以忽略): 是:Y 否:不传或者随意传") @RequestParam(required = false) String updateNil) {        int addResult = dpProcessService.modify(dpProcess, updateNil);        if (addResult > 0) {            return new Result(CommonCode.SUCCESS, "更新成功!");        }        return new Result(CommonCode.FAIL, "更新失败!");    }

5.3 Service

没啥好说的,就是一个接口。

/**     * @create 2021-07-08 更新 数据处理     * @param dpProcess 数据处理 模型     * @param updateNil 全字段更新(新增时此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}     * @return     */    int modify(DpProcess dpProcess, String updateNil);

5.4 Service 实现类

 DpRecord:数据处理记录,不是本文重点,此处可直接忽略,相关说明 待 数据流程处理文章中提现。

/**     * @create  2021-07-08 更新 数据处理     * @param dpProcess 数据处理 模型     * @param updateNil 全字段更新(新增时此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}     * @return     */    @Override    public int modify(DpProcess dpProcess, String updateNil){        if(dpProcess == null){            throw new ServiceException("数据处理模型不能为空!");        }        // 走更新方法        // 通过id查询数据处理 详情        DpProcess orignDpProcess = this.detail(dpProcess.getId());        if(dpProcess == null){            throw new ServiceException("数据处理模型信息不能为空!");        }        // 如果当前任务已存在,需要先进行取消        if("0".equals(dpProcess.getEnabled())){            if(defaultSchedulingConfigurer.hasTask(dpProcess.getId())){                defaultSchedulingConfigurer.cancelTriggerTask(dpProcess.getId());            }            // 根据数据处理ID查看数据库中是否有需要执行的数据处理记录            DpRecord dpRecord = dpRecordService.getNeedExecRecordByDppId(dpProcess.getId());            // 如果数据处理记录信息为空,则进行新增            if(dpRecord != null){                // 设置结束时间为当前时间                dpRecord.setEndTime(new Date());                // 运行失败                dpRecord.setSucceed("2");                dpRecord.setFailedResult("用户取消操作");            }            // 对数据处理记录进行更新或者保存            dpRecordService.addOrUpdate(dpRecord, null);        }        // 限制输出集合不能为空        dpProcess.setOutCols(StringUtils.isNotBlank(dpProcess.getOutCols()) ? dpProcess.getOutCols() : orignDpProcess.getOutCols());        if(StringUtils.isBlank(dpProcess.getOutCols())){            throw new ServiceException("数据影响集合不能为空!");        }        // 输入集合统一处理        operInclos(dpProcess, orignDpProcess.getInCols());        // 全字段更新        if(SystemConst.Whether.Yes.getCode().equals(updateNil)){            if(StringUtils.isBlank(dpProcess.getRemark())){                throw new ServiceException("数据处理备注不能为空!");            }            // 备注不能小于20字            if(dpProcess.getRemark().length() < 20){                throw new ServiceException("数据处理备注不能小于20字!");            }            return dpProcessMapper.alwaysUpdateSomeColumnById(dpProcess);        }        // 数据处理代码自动填充        dpProcess.setCode(StringUtils.isBlank(dpProcess.getCode()) ? orignDpProcess.getCode() : dpProcess.getCode());        return dpProcessMapper.updateById(dpProcess);    }

operInclos() : 处理输入集合的方法

/** * @create 输入集合统一处理  2021/7/11 14:13 * @param dpProcess 新数据处理对象 * @param oldClos 原数据处理对象中的而输入集合 * @return */private void operInclos(DpProcess dpProcess, String oldClos) {    // 新数据处理对象中的输入集合    String inCols = dpProcess.getInCols();    // 若新数据处理对象中的输入集合没有值,则直接跳过,不进行操作    if(StringUtils.isNotBlank(inCols)){        if(dpProcess.getInCols().contains(dpProcess.getOutCols())){            throw new ServiceException("数据处理流程配置输入流程调用了输出集合!");        }        // 数据类型转换        Set set = new HashSet(Arrays.asList(inCols.split(",")));        // 循环遍历输入集合        for (String inClo : set) {            // 最终需要遍历的list            List childFinalList = new ArrayList<>();            // 从redis中获取当前集合的影响关系            String dpProcessJson = (String) redisUtil.get(inClo);            // 如果redis中存储的集合影响关系不为空,做简单的遍历去重处理            if(StringUtils.isNotBlank(dpProcessJson)){                // redis中存储的集合影响关系列表                List children = new ArrayList<>();                // 进行数据类型转换                children = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);                for (DpProcessVo dpProcessVo1 : children) {                    if(dpProcess.getId().equals(dpProcessVo1.getId())){                        continue;                    }                    childFinalList.add(dpProcessVo1);                }                // 添加本次影响的集合                DpProcessVo dpProcess1 = new DpProcessVo();                dpProcess1.setId(dpProcess.getId());                dpProcess1.setOutCols(dpProcess.getOutCols());                childFinalList.add(dpProcess1);            }            // 如果redis中没有此输入集合的影响关系,则可以直接进行添加            else{                DpProcessVo dpProcess1 = new DpProcessVo();                dpProcess1.setId(dpProcess.getId());                dpProcess1.setOutCols(dpProcess.getOutCols());                childFinalList.add(dpProcess1);            }            // 验证数据处理流程配置输入流程是否调用了输出集合            Stack nodeStack = new Stack<>();            // 设置模型            DpProcessVo dpProcessVoTop = new DpProcessVo();            dpProcessVoTop.setOutCols(inClo);            dpProcessVoTop.setId(dpProcess.getId());            nodeStack.add(dpProcessVoTop);            // 遍历需要进行死链校验的数据            for (DpProcessVo dpProcessVo : childFinalList) {                // 是否添加标识(默认为添加,如果集合为死链,则进行提示)                boolean addFlag = true;                // 循环遍历栈                for (DpProcessVo processVo : nodeStack) {                    if(processVo.getOutCols().equals(dpProcessVo.getOutCols())){                        addFlag = false;                        break;                    }                }                if(!addFlag){                    throw new ServiceException("数据处理流程配置输入流程调用了输出集合!");                }                // 将dpProcessVo推到这个堆栈的顶部                nodeStack.push(dpProcessVo);                // 验证数据处理流程配置输入流程是否调用了输出集合                invaldClosInfo(nodeStack);                // 移除此堆栈顶部的对象并将该对象作为此函数的值返回                nodeStack.pop();            }        }        // 处理需要删除的集合        dealNeedDeleteCols(dpProcess, oldClos, set);        // 获取并设置最终的集合名称        String finallyCols = StringUtils.join(set.toArray(), ",");        dpProcess.setInCols(finallyCols);        // 能走到这一步,说明所有的集合没有问题,可以进行更新操作了(再一次遍历是为了和上面的校验分开,避免部分数据被更新)        for (String inClo : set) {            List dpProcessVoList = new ArrayList<>();            // 首先获取当前集合影响的数据处理对象            String dpProcessJson = (String) redisUtil.get(inClo);            if(StringUtils.isBlank(dpProcessJson)){                DpProcessVo dpProcessVo = new DpProcessVo();                dpProcessVo.setId(dpProcess.getId());                dpProcessVo.setOutCols(dpProcess.getOutCols());                dpProcessVoList.add(dpProcessVo);                // 进行数据的存储                redisUtil.set(inClo, JSONArray.toJSON(dpProcessVoList).toString());                continue;            }            // redis中原来存储的信息            List dpProcessVos = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);            // 把数据处理对象转换为HashSet            HashSet hashSet = new HashSet(dpProcessVos);            // 当前集合影响的 其他集合列表            List childFinalList = new ArrayList<>();            // 遍历redis中存储的集合影响关系,并进行简单去重处理            for (DpProcessVo dpProcessVo : hashSet) {                if(dpProcessVo.getId().equals(dpProcess.getId())){                    continue;                }                childFinalList.add(dpProcessVo);            }            // 添加上本次影响的集合            DpProcessVo dpProcessVo = new DpProcessVo();            dpProcessVo.setId(dpProcess.getId());            dpProcessVo.setOutCols(dpProcess.getOutCols());            // 添加当前数据数据对象            childFinalList.add(dpProcessVo);            // 进行数据的存储            redisUtil.set(inClo, JSONArray.toJSON(childFinalList).toString());        }    }}

invaldClosInfo() : 验证数据处理流程配置输入流程是否调用了输出集合

/** * @create 验证数据处理流程配置输入流程是否调用了输出集合  2021/7/20 22:10 * @param nodeStack 深度遍历栈 * @return void */public void invaldClosInfo(Stack nodeStack) {    // 查看此堆栈顶部的对象而不将其从堆栈中移除    DpProcessVo dpProcessVo = nodeStack.peek();    // 从redis中查找此集合影响的流程关系    String dpProcessJson = (String) redisUtil.get(dpProcessVo.getOutCols());    // 如果集合没有影响其他集合,则直接返回    if(StringUtils.isBlank(dpProcessJson)){        return;    }    //获得节点的子节点,对于二叉树就是获得节点的左子结点和右子节点    List children = new ArrayList<>();    // redis中原来存储的信息    children = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);    // 遍历集合影响的集合关系    for (DpProcessVo dpProcessVo1 : children) {        boolean addFlag = true;        for (DpProcessVo processVo : nodeStack) {            if(processVo.getOutCols().equals(dpProcessVo1.getOutCols())){                addFlag = false;                break;            }        }        if(!addFlag){            throw new ServiceException("数据处理流程配置输入流程调用了输出集合!");        }        // 将dpProcessVo推到这个堆栈的顶部        nodeStack.push(dpProcessVo1);        // 验证数据处理流程配置输入流程是否调用了输出集合        invaldClosInfo(nodeStack);        // 移除此堆栈顶部的对象并将该对象作为此函数的值返回        nodeStack.pop();    }}

dealNeedDeleteCols() : 主要处理--原数据为 A 集合影响 B 集合,修改为 C 集合影响了 B 集合,此时需要删除 A 对 B的影响关系

/** * @create 处理需要删除的集合 2021/7/20 17:58 * @param dpProcess 数据处理模型 * @param oldClos 原来的数据处理模型中的集合信息 * @param set 最新的集合名称信息 * @return void */private void dealNeedDeleteCols(DpProcess dpProcess, String oldClos, Set set) {    if(StringUtils.isBlank(oldClos)){        return;    }    // 获取去重后的集合数组    List newColsList = new ArrayList<>(set);    // 原来的集合数组    List oldColsList = Arrays.asList(oldClos.split(","));    // 获取两个集合的差集    List reduceList = oldColsList.stream().filter(item -> !newColsList.contains(item)).collect(toList());    if(reduceList == null || reduceList.size() == 0){        return;    }    for (String clos : reduceList) {        // 获取redis中的集合        String dpProcessJson = (String) redisUtil.get(clos);        if(StringUtils.isBlank(dpProcessJson)){            continue;        }        // redis中原来存储的信息        List dpProcessVos = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);        // 遍历删除的集合中影响的流程ID        HashSet hashSet = new HashSet(dpProcessVos);        Iterator it = hashSet.iterator();        while(it.hasNext()){            DpProcessVo dpProcessVo = it.next();            if(dpProcessVo.getId().equals(dpProcess.getId())){                it.remove();            }        }        // 如果当前集合影响的流程为空,则进行删除        if(hashSet.isEmpty()){            // 进行数据的存储            redisUtil.delete(clos);            continue;        }        // 进行数据的存储        redisUtil.set(clos, JSONArray.toJSON(hashSet.toArray()).toString());    }}

6.测试

 可通过单元测试等多种方式,本文提供简单的测试数据。

{    "category": "ly",    "code": "F",    "createdBy": "",    "createdTime": null,    "enabled": "1",    "id": "5",    "inCols": "D",    "name": "F",    "outCols": "L",    "remark": "F",    "revision": 0,    "status": 0,    "updatedBy": "",    "updatedTime": null  }

感谢各位的阅读!关于"java中如何避免集合死链调用"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

0