欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java中避免集合死鏈調(diào)用詳情

 更新時間:2021年09月24日 08:47:44   作者:學(xué)海無涯  
這篇文章主要介紹了java中避免集合死鏈調(diào)用,開發(fā)過程中, 一些集合 的變動會觸發(fā)任務(wù)去 改變 其他的集合 ,為了保障任務(wù)的正確執(zhí)行,應(yīng)避免出現(xiàn)死循環(huán)調(diào)用,即對 集合之間的影響關(guān)系 進(jìn)行一些限制,下面文章就來看看這種問題的避免

1. 前言

 開發(fā)過程中, 一些集合 的變動會觸發(fā)任務(wù)去 改變 其他的集合 ,為了保障任務(wù)的正確執(zhí)行,應(yīng)避免出現(xiàn)死循環(huán)調(diào)用,即對 集合之間的影響關(guān)系 進(jìn)行一些限制。怕日后遺忘,特在此記錄。

2. 場景

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

3. 環(huán)境

3.1 開發(fā)環(huán)境準(zhǔn)備

  • JDK 1.8
  • SpringBoot 2.x
  • Mysql 8
  • redis

3.2 數(shù)據(jù)準(zhǔn)備

3.2.1 Mysql數(shù)據(jù)庫表及數(shù)據(jù)

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=房地產(chǎn)',
  `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 '狀態(tài) 數(shù)據(jù)狀態(tài):0=正常,1=刪除,失效',
  `CREATED_BY` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '創(chuàng)建人',
  `CREATED_TIME` datetime DEFAULT NULL COMMENT '創(chuàng)建時間',
  `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='數(shù)據(jù)處理 ';


dp_process 表中的數(shù)據(jù)

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庫數(shù)據(jù)

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. 解決方式

通過遞歸的方式循環(huán)查詢、對比。

本例主要牽扯到的知識點(diǎn)有:

  • Stack (棧,先進(jìn)后出)
  • 遞歸
  • redis簡單增刪操作

本文以 修改方法 代碼為例,介紹如何實(shí)現(xiàn)防死鏈調(diào)用,非常簡單。

/**
     * @create  2021-07-08 更新 數(shù)據(jù)處理
     * @param dpProcess 數(shù)據(jù)處理 模型
     * @param updateNil 全字段更新(新增時此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}
     * @return
     */
    @Override
    public int modify(DpProcess dpProcess, String updateNil){
        
        // **省略一堆代碼**

        // 輸入集合統(tǒng)一處理


operInclos(dpProcess, orignDpProcess.getInCols());

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

 operInclos() 方法 : 重點(diǎn) ,主要做了數(shù)據(jù)校驗(yàn)、redis中數(shù)據(jù)更新等一系列操作

/**
     * @create 輸入集合統(tǒng)一處理 2021/7/11 14:13
     * @param dpProcess 新數(shù)據(jù)處理對象
     * @param oldClos 原數(shù)據(jù)處理對象中的輸入集合
     * @return
     */
    private void operInclos(DpProcess dpProcess, String oldClos) {
        // 新數(shù)據(jù)處理對象中的輸入集合
        String inCols = dpProcess.getInCols();

        // 若新數(shù)據(jù)處理對象中的輸入集合沒有值,則直接跳過,不進(jìn)行操作
        if(StringUtils.isNotBlank(inCols)){
            if(dpProcess.getInCols().contains(dpProcess.getOutCols())){
                throw new ServiceException("數(shù)據(jù)處理流程配置輸入流程調(diào)用了輸出集合!");
            }

            // 數(shù)據(jù)類型轉(zhuǎn)換
            Set<String> set = new HashSet(Arrays.asList(inCols.split(",")));

            // 循環(huán)遍歷輸入集合
            for (String inClo : set) {

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

                // 從redis中獲取當(dāng)前集合的影響關(guān)系
                String dpProcessJson = (String) redisUtil.get(inClo);

                // 如果redis中存儲的集合影響關(guān)系不為空,做簡單的遍歷去重處理
                if(StringUtils.isNotBlank(dpProcessJson)){

                    // redis中存儲的集合影響關(guān)系列表
                    List<DpProcessVo> children = new ArrayList<>();

                    // 進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換
                    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中沒有此輸入集合的影響關(guān)系,則可以直接進(jìn)行添加
                else{
                    DpProcessVo dpProcess1 = new DpProcessVo();
                    dpProcess1.setId(dpProcess.getId());
                    dpProcess1.setOutCols(dpProcess.getOutCols());
                    childFinalList.add(dpProcess1);
                }

                // 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合
                Stack<DpProcessVo> nodeStack = new Stack<>();
                // 設(shè)置模型
                DpProcessVo dpProcessVoTop = new DpProcessVo();
                dpProcessVoTop.setOutCols(inClo);
                dpProcessVoTop.setId(dpProcess.getId());
                nodeStack.add(dpProcessVoTop);

                // 遍歷需要進(jìn)行死鏈校驗(yàn)的數(shù)據(jù)
                for (DpProcessVo dpProcessVo : childFinalList) {

                    // 是否添加標(biāo)識(默認(rèn)為添加,如果集合為死鏈,則進(jìn)行提示)
                    boolean addFlag = true;

                    // 循環(huán)遍歷棧
                    for (DpProcessVo processVo : nodeStack) {
                        if(processVo.getOutCols().equals(dpProcessVo.getOutCols())){
                            addFlag = false;
                            break;
                        }
                    }
                    if(!addFlag){

                        throw new ServiceException("數(shù)據(jù)處理流程配置輸入流程調(diào)用了輸出集合!");
                    }
                    // 將dpProcessVo推到這個堆棧的頂部
                    nodeStack.push(dpProcessVo);

                    // 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合
                    invaldClosInfo(nodeStack);

                    // 移除此堆棧頂部的對象并將該對象作為此函數(shù)的值返回
                    nodeStack.pop();

                }
            }

            // 處理需要刪除的集合
            dealNeedDeleteCols(dpProcess, oldClos, set);

            // 獲取并設(shè)置最終的集合名稱
            String finallyCols = StringUtils.join(set.toArray(), ",");
            dpProcess.setInCols(finallyCols);

            // 省略一堆更新redis的操作
        }
    }


 invaldClosInfo()方法: 遞歸深度遍歷

/**
     * @create 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合  2021/7/20 22:10
     * @param nodeStack 深度遍歷棧
     * @return void
     */
    public void invaldClosInfo(Stack<DpProcessVo> nodeStack) {

        // 查看此堆棧頂部的對象而不將其從堆棧中移除
        DpProcessVo dpProcessVo = nodeStack.peek();

        // 從redis中查找此集合影響的流程關(guān)系
        String dpProcessJson = (String) redisUtil.get(dpProcessVo.getOutCols());
        // 如果集合沒有影響其他集合,則直接返回
        if(StringUtils.isBlank(dpProcessJson)){
            return;
        }

        //獲得節(jié)點(diǎn)的子節(jié)點(diǎn),對于二叉樹就是獲得節(jié)點(diǎn)的左子結(jié)點(diǎn)和右子節(jié)點(diǎn)
        List<DpProcessVo> children = new ArrayList<>();
        // redis中原來存儲的信息
        children = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);

        // 遍歷集合影響的集合關(guān)系
        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("數(shù)據(jù)處理流程配置輸入流程調(diào)用了輸出集合!");
            }

            // 將dpProcessVo推到這個堆棧的頂部
            nodeStack.push(dpProcessVo1);

            // 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合
            invaldClosInfo(nodeStack);

            // 移除此堆棧頂部的對象并將該對象作為此函數(shù)的值返回
            nodeStack.pop();
        }
    }

5.完整代碼

記錄代碼,方便日后復(fù)習(xí)、調(diào)用、重構(gòu)。

5.1 Model

 模型主要分兩部分:數(shù)據(jù)處理模型和簡化版的數(shù)據(jù)處理模型。

 DpProcess:數(shù)據(jù)處理模型,數(shù)據(jù)完整的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;

/**
 * <p>
 * 數(shù)據(jù)處理 
 * </p>
 *
 * @since 2021-07-08
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="DpProcess對象", description="數(shù)據(jù)處理 ")
@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=房地產(chǎn)")
    @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 = "狀態(tài) 數(shù)據(jù)狀態(tài):0=正常,1=刪除,失效")
    @TableField(value = "STATUS", fill = FieldFill.INSERT)
    private Integer status;

    @ApiModelProperty(value = "創(chuàng)建人")
    @TableField(value = "CREATED_BY", fill = FieldFill.INSERT)
    private String createdBy;

    @ApiModelProperty(value = "創(chuàng)建時間")
    @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: 數(shù)據(jù)處理簡單模型,處理redis數(shù)據(jù)結(jié)構(gòu)數(shù)據(jù)。

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="數(shù)據(jù)處理簡單模型 ")
public class DpProcessVo{

    @ApiModelProperty(value = "ID")
    private String id;

    @ApiModelProperty(value = "影響集合")
    private String outCols;

}

5.2 Controller

updateNil:讓用戶選擇使用那種更新方式,也可以把接口一拆為二,主要看個人習(xí)慣。

/**
     * @create  2021-07-08 更新 數(shù)據(jù)處理
     * @param dpProcess 數(shù)據(jù)處理 模型
     * @param updateNil 全字段更新(新增時此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}
     * @return
     */
    @ApiOperation(value="更新",notes = "更新")
    @PostMapping("/modify")
    public Result modify(
            @ApiParam(name = "dpProcess", value = "數(shù)據(jù)處理 模型", 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 更新 數(shù)據(jù)處理
     * @param dpProcess 數(shù)據(jù)處理 模型
     * @param updateNil 全字段更新(新增時此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}
     * @return
     */
    int modify(DpProcess dpProcess, String updateNil);

5.4 Service 實(shí)現(xiàn)類

 DpRecord:數(shù)據(jù)處理記錄,不是本文重點(diǎn),此處可直接忽略,相關(guān)說明 待 數(shù)據(jù)流程處理文章中提現(xiàn)。

/**
     * @create  2021-07-08 更新 數(shù)據(jù)處理
     * @param dpProcess 數(shù)據(jù)處理 模型
     * @param updateNil 全字段更新(新增時此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}
     * @return
     */
    @Override
    public int modify(DpProcess dpProcess, String updateNil){
        if(dpProcess == null){
            throw new ServiceException("數(shù)據(jù)處理模型不能為空!");
        }
        // 走更新方法
        // 通過id查詢數(shù)據(jù)處理 詳情
        DpProcess orignDpProcess = this.detail(dpProcess.getId());
        if(dpProcess == null){
            throw new ServiceException("數(shù)據(jù)處理模型信息不能為空!");
        }

        // 如果當(dāng)前任務(wù)已存在,需要先進(jìn)行取消
        if("0".equals(dpProcess.getEnabled())){
            if(defaultSchedulingConfigurer.hasTask(dpProcess.getId())){
                defaultSchedulingConfigurer.cancelTriggerTask(dpProcess.getId());
            }
            // 根據(jù)數(shù)據(jù)處理ID查看數(shù)據(jù)庫中是否有需要執(zhí)行的數(shù)據(jù)處理記錄
            DpRecord dpRecord = dpRecordService.getNeedExecRecordByDppId(dpProcess.getId());
            // 如果數(shù)據(jù)處理記錄信息為空,則進(jìn)行新增
            if(dpRecord != null){
                // 設(shè)置結(jié)束時間為當(dāng)前時間
                dpRecord.setEndTime(new Date());
                // 運(yùn)行失敗
                dpRecord.setSucceed("2");
                dpRecord.setFailedResult("用戶取消操作");
            }
            // 對數(shù)據(jù)處理記錄進(jìn)行更新或者保存
            dpRecordService.addOrUpdate(dpRecord, null);
        }

        // 限制輸出集合不能為空
        dpProcess.setOutCols(StringUtils.isNotBlank(dpProcess.getOutCols()) ? dpProcess.getOutCols() : orignDpProcess.getOutCols());
        if(StringUtils.isBlank(dpProcess.getOutCols())){
            throw new ServiceException("數(shù)據(jù)影響集合不能為空!");
        }

        // 輸入集合統(tǒng)一處理
        operInclos(dpProcess, orignDpProcess.getInCols());

        // 全字段更新
        if(SystemConst.Whether.Yes.getCode().equals(updateNil)){
            if(StringUtils.isBlank(dpProcess.getRemark())){
                throw new ServiceException("數(shù)據(jù)處理備注不能為空!");
            }
            // 備注不能小于20字
            if(dpProcess.getRemark().length() < 20){
                throw new ServiceException("數(shù)據(jù)處理備注不能小于20字!");
            }
            return dpProcessMapper.alwaysUpdateSomeColumnById(dpProcess);
        }
        // 數(shù)據(jù)處理代碼自動填充
        dpProcess.setCode(StringUtils.isBlank(dpProcess.getCode()) ? orignDpProcess.getCode() : dpProcess.getCode());

        return dpProcessMapper.updateById(dpProcess);
    }

operInclos() : 處理輸入集合的方法

/**
 * @create 輸入集合統(tǒng)一處理  2021/7/11 14:13
 * @param dpProcess 新數(shù)據(jù)處理對象
 * @param oldClos 原數(shù)據(jù)處理對象中的而輸入集合
 * @return
 */
private void operInclos(DpProcess dpProcess, String oldClos) {
    // 新數(shù)據(jù)處理對象中的輸入集合
    String inCols = dpProcess.getInCols();

    // 若新數(shù)據(jù)處理對象中的輸入集合沒有值,則直接跳過,不進(jìn)行操作
    if(StringUtils.isNotBlank(inCols)){
        if(dpProcess.getInCols().contains(dpProcess.getOutCols())){
            throw new ServiceException("數(shù)據(jù)處理流程配置輸入流程調(diào)用了輸出集合!");
        }

        // 數(shù)據(jù)類型轉(zhuǎn)換
        Set<String> set = new HashSet(Arrays.asList(inCols.split(",")));

        // 循環(huán)遍歷輸入集合
        for (String inClo : set) {

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

            // 從redis中獲取當(dāng)前集合的影響關(guān)系
            String dpProcessJson = (String) redisUtil.get(inClo);

            // 如果redis中存儲的集合影響關(guān)系不為空,做簡單的遍歷去重處理
            if(StringUtils.isNotBlank(dpProcessJson)){

                // redis中存儲的集合影響關(guān)系列表
                List<DpProcessVo> children = new ArrayList<>();

                // 進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換
                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中沒有此輸入集合的影響關(guān)系,則可以直接進(jìn)行添加
            else{
                DpProcessVo dpProcess1 = new DpProcessVo();
                dpProcess1.setId(dpProcess.getId());
                dpProcess1.setOutCols(dpProcess.getOutCols());
                childFinalList.add(dpProcess1);
            }

            // 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合
            Stack<DpProcessVo> nodeStack = new Stack<>();
            // 設(shè)置模型
            DpProcessVo dpProcessVoTop = new DpProcessVo();
            dpProcessVoTop.setOutCols(inClo);
            dpProcessVoTop.setId(dpProcess.getId());
            nodeStack.add(dpProcessVoTop);

            // 遍歷需要進(jìn)行死鏈校驗(yàn)的數(shù)據(jù)
            for (DpProcessVo dpProcessVo : childFinalList) {

                // 是否添加標(biāo)識(默認(rèn)為添加,如果集合為死鏈,則進(jìn)行提示)
                boolean addFlag = true;

                // 循環(huán)遍歷棧
                for (DpProcessVo processVo : nodeStack) {
                    if(processVo.getOutCols().equals(dpProcessVo.getOutCols())){
                        addFlag = false;
                        break;
                    }
                }
                if(!addFlag){

                    throw new ServiceException("數(shù)據(jù)處理流程配置輸入流程調(diào)用了輸出集合!");
                }
                // 將dpProcessVo推到這個堆棧的頂部
                nodeStack.push(dpProcessVo);

                // 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合
                invaldClosInfo(nodeStack);

                // 移除此堆棧頂部的對象并將該對象作為此函數(shù)的值返回
                nodeStack.pop();

            }
        }

        // 處理需要刪除的集合
        dealNeedDeleteCols(dpProcess, oldClos, set);

        // 獲取并設(shè)置最終的集合名稱
        String finallyCols = StringUtils.join(set.toArray(), ",");
        dpProcess.setInCols(finallyCols);

        // 能走到這一步,說明所有的集合沒有問題,可以進(jìn)行更新操作了(再一次遍歷是為了和上面的校驗(yàn)分開,避免部分?jǐn)?shù)據(jù)被更新)
        for (String inClo : set) {

            List<DpProcessVo> dpProcessVoList = new ArrayList<>();
            // 首先獲取當(dāng)前集合影響的數(shù)據(jù)處理對象
            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);
                // 進(jìn)行數(shù)據(jù)的存儲
                redisUtil.set(inClo, JSONArray.toJSON(dpProcessVoList).toString());
                continue;
            }

            // redis中原來存儲的信息
            List<DpProcessVo> dpProcessVos = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);

            // 把數(shù)據(jù)處理對象轉(zhuǎn)換為HashSet
            HashSet<DpProcessVo> hashSet = new HashSet(dpProcessVos);
            // 當(dāng)前集合影響的 其他集合列表
            List<DpProcessVo> childFinalList = new ArrayList<>();

            // 遍歷redis中存儲的集合影響關(guān)系,并進(jìn)行簡單去重處理
            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());
            // 添加當(dāng)前數(shù)據(jù)數(shù)據(jù)對象
            childFinalList.add(dpProcessVo);
            // 進(jìn)行數(shù)據(jù)的存儲
            redisUtil.set(inClo, JSONArray.toJSON(childFinalList).toString());
        }
    }
}

invaldClosInfo() : 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合

/**
 * @create 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合  2021/7/20 22:10
 * @param nodeStack 深度遍歷棧
 * @return void
 */
public void invaldClosInfo(Stack<DpProcessVo> nodeStack) {

    // 查看此堆棧頂部的對象而不將其從堆棧中移除
    DpProcessVo dpProcessVo = nodeStack.peek();

    // 從redis中查找此集合影響的流程關(guān)系
    String dpProcessJson = (String) redisUtil.get(dpProcessVo.getOutCols());
    // 如果集合沒有影響其他集合,則直接返回
    if(StringUtils.isBlank(dpProcessJson)){
        return;
    }

    //獲得節(jié)點(diǎn)的子節(jié)點(diǎn),對于二叉樹就是獲得節(jié)點(diǎn)的左子結(jié)點(diǎn)和右子節(jié)點(diǎn)
    List<DpProcessVo> children = new ArrayList<>();
    // redis中原來存儲的信息
    children = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);

    // 遍歷集合影響的集合關(guān)系
    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("數(shù)據(jù)處理流程配置輸入流程調(diào)用了輸出集合!");
        }

        // 將dpProcessVo推到這個堆棧的頂部
        nodeStack.push(dpProcessVo1);

        // 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合
        invaldClosInfo(nodeStack);

        // 移除此堆棧頂部的對象并將該對象作為此函數(shù)的值返回
        nodeStack.pop();
    }
}

dealNeedDeleteCols() : 主要處理--原數(shù)據(jù)為 A 集合影響 B 集合,修改為 C 集合影響了 B 集合,此時需要刪除 A 對 B的影響關(guān)系

/**
 * @create 處理需要刪除的集合 2021/7/20 17:58
 * @param dpProcess 數(shù)據(jù)處理模型
 * @param oldClos 原來的數(shù)據(jù)處理模型中的集合信息
 * @param set 最新的集合名稱信息
 * @return void
 */
private void dealNeedDeleteCols(DpProcess dpProcess, String oldClos, Set<String> set) {

    if(StringUtils.isBlank(oldClos)){
        return;
    }
    // 獲取去重后的集合數(shù)組
    List<String> newColsList = new ArrayList<>(set);

    // 原來的集合數(shù)組
    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();
            }
        }
        // 如果當(dāng)前集合影響的流程為空,則進(jìn)行刪除
        if(hashSet.isEmpty()){
            // 進(jìn)行數(shù)據(jù)的存儲
            redisUtil.delete(clos);
            continue;
        }
        // 進(jìn)行數(shù)據(jù)的存儲
        redisUtil.set(clos, JSONArray.toJSON(hashSet.toArray()).toString());
    }

}

6.測試

 可通過單元測試等多種方式,本文提供簡單的測試數(shù)據(jù)。

{
    "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
  }

到此這篇關(guān)于java中避免集合死鏈調(diào)用詳情的文章就介紹到這了,更多相關(guān)java中避免集合死鏈調(diào)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java經(jīng)驗(yàn)點(diǎn)滴:處理沒有被捕獲的異常

    Java經(jīng)驗(yàn)點(diǎn)滴:處理沒有被捕獲的異常

    Java經(jīng)驗(yàn)點(diǎn)滴:處理沒有被捕獲的異常...
    2006-12-12
  • Maven項(xiàng)目更換本地倉庫過程圖解

    Maven項(xiàng)目更換本地倉庫過程圖解

    這篇文章主要介紹了Maven項(xiàng)目更換本地倉庫過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • java實(shí)現(xiàn)貪吃蛇游戲代碼(附完整源碼)

    java實(shí)現(xiàn)貪吃蛇游戲代碼(附完整源碼)

    這篇文章主要介紹了java實(shí)現(xiàn)貪吃蛇游戲代碼(附完整源碼),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • Springboot?異步任務(wù)和定時任務(wù)的異步處理

    Springboot?異步任務(wù)和定時任務(wù)的異步處理

    本文介紹了Springboot異步任務(wù)和定時任務(wù)的異步處理,Springboot?中,異步任務(wù)和定時任務(wù)是經(jīng)常遇到的處理問題方式,為了能夠用好這兩項(xiàng)配置,不干擾正常的業(yè)務(wù),需要對其進(jìn)行異步化配置。怎么設(shè)置合理的異步處理線程就是其核心和關(guān)鍵,下文詳情需要的朋友可以參考下
    2022-05-05
  • org.springframework.web.client.ResourceAccessException資源訪問錯誤的解決方法

    org.springframework.web.client.ResourceAccessException資源訪問錯誤

    本文主要介紹了org.springframework.web.client.ResourceAccessException資源訪問錯誤的解決方法,首先需要分析異常的詳細(xì)信息,以確定具體的錯誤原因,感興趣的可以了解一下
    2024-05-05
  • Java多態(tài)用法與注意點(diǎn)實(shí)例分析

    Java多態(tài)用法與注意點(diǎn)實(shí)例分析

    這篇文章主要介紹了Java多態(tài)用法與注意點(diǎn),結(jié)合實(shí)例形式分析了java多態(tài)相關(guān)的向上轉(zhuǎn)型、向下轉(zhuǎn)型、隱藏等相關(guān)操作技巧,需要的朋友可以參考下
    2019-08-08
  • Java并發(fā)內(nèi)存模型詳情

    Java并發(fā)內(nèi)存模型詳情

    這篇文章主要介紹了Java并發(fā)內(nèi)存模型,Java是一門支持多線程執(zhí)行的語言,要編寫正確的并發(fā)程序,了解Java內(nèi)存模型是重要前提。而了解硬件內(nèi)存模型有助于理解程序的執(zhí)行,下面文章就來看看詳細(xì)內(nèi)容吧
    2021-10-10
  • 淺談Java中格式化輸出

    淺談Java中格式化輸出

    這篇文章主要介紹了Java中格式化輸出,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • JavaScript base64 與 File 之間的互轉(zhuǎn)(操作方法)

    JavaScript base64 與 File 之間的互轉(zhuǎn)(操作方法)

    在JavaScript 中,可以使用 Blob 對象將 base64 字符串轉(zhuǎn)換為 File 對象,這篇文章主要介紹了JavaScript base64 與 File之間的互轉(zhuǎn),需要的朋友可以參考下
    2024-05-05
  • 解決運(yùn)行jar包出錯:ClassNotFoundException問題

    解決運(yùn)行jar包出錯:ClassNotFoundException問題

    這篇文章主要介紹了解決運(yùn)行jar包出錯:ClassNotFoundException問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評論