我的编程空间,编程开发者的网络收藏夹
学习永远不晚

java中避免集合死链调用详情

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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库数据

key Value
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简单增删操作

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



    @Override
    public int modify(DpProcess dpProcess, String updateNil){
        
        // **省略一堆代码**

        // 输入集合统一处理


operInclos(dpProcess, orignDpProcess.getInCols());

        // **省略一堆代码**
    }

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



    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<String> set = new HashSet(Arrays.asList(inCols.split(",")));

            // 循环遍历输入集合
            for (String inClo : set) {

                // 最终需要遍历的list
                List<DpProcessVo> childFinalList = new ArrayList<>();

                // 从redis中获取当前集合的影响关系
                String dpProcessJson = (String) redisUtil.get(inClo);

                // 如果redis中存储的集合影响关系不为空,做简单的遍历去重处理
                if(StringUtils.isNotBlank(dpProcessJson)){

                    // redis中存储的集合影响关系列表
                    List<DpProcessVo> 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<DpProcessVo> 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()方法: 递归深度遍历



    public void invaldClosInfo(Stack<DpProcessVo> nodeStack) {

        // 查看此堆栈顶部的对象而不将其从堆栈中移除
        DpProcessVo dpProcessVo = nodeStack.peek();

        // 从redis中查找此集合影响的流程关系
        String dpProcessJson = (String) redisUtil.get(dpProcessVo.getOutCols());
        // 如果集合没有影响其他集合,则直接返回
        if(StringUtils.isBlank(dpProcessJson)){
            return;
        }

        //获得节点的子节点,对于二叉树就是获得节点的左子结点和右子节点
        List<DpProcessVo> 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;


@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:让用户选择使用那种更新方式,也可以把接口一拆为二,主要看个人习惯。



    @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

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



    int modify(DpProcess dpProcess, String updateNil);

5.4 Service 实现类

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



    @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() : 处理输入集合的方法



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<String> set = new HashSet(Arrays.asList(inCols.split(",")));

        // 循环遍历输入集合
        for (String inClo : set) {

            // 最终需要遍历的list
            List<DpProcessVo> childFinalList = new ArrayList<>();

            // 从redis中获取当前集合的影响关系
            String dpProcessJson = (String) redisUtil.get(inClo);

            // 如果redis中存储的集合影响关系不为空,做简单的遍历去重处理
            if(StringUtils.isNotBlank(dpProcessJson)){

                // redis中存储的集合影响关系列表
                List<DpProcessVo> 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<DpProcessVo> 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<DpProcessVo> 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<DpProcessVo> dpProcessVos = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);

            // 把数据处理对象转换为HashSet
            HashSet<DpProcessVo> hashSet = new HashSet(dpProcessVos);
            // 当前集合影响的 其他集合列表
            List<DpProcessVo> 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() : 验证数据处理流程配置输入流程是否调用了输出集合



public void invaldClosInfo(Stack<DpProcessVo> nodeStack) {

    // 查看此堆栈顶部的对象而不将其从堆栈中移除
    DpProcessVo dpProcessVo = nodeStack.peek();

    // 从redis中查找此集合影响的流程关系
    String dpProcessJson = (String) redisUtil.get(dpProcessVo.getOutCols());
    // 如果集合没有影响其他集合,则直接返回
    if(StringUtils.isBlank(dpProcessJson)){
        return;
    }

    //获得节点的子节点,对于二叉树就是获得节点的左子结点和右子节点
    List<DpProcessVo> 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的影响关系



private void dealNeedDeleteCols(DpProcess dpProcess, String oldClos, Set<String> set) {

    if(StringUtils.isBlank(oldClos)){
        return;
    }
    // 获取去重后的集合数组
    List<String> newColsList = new ArrayList<>(set);

    // 原来的集合数组
    List<String> oldColsList = Arrays.asList(oldClos.split(","));

    // 获取两个集合的差集
    List<String> 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<DpProcessVo> dpProcessVos = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);
        // 遍历删除的集合中影响的流程ID
        HashSet<DpProcessVo> hashSet = new HashSet(dpProcessVos);
        Iterator<DpProcessVo> 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中避免集合死链调用详情的文章就介绍到这了,更多相关java中避免集合死链调用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

java中避免集合死链调用详情

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录