Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[错误报告]: 描述 一个循环内,重复查询一个sql,会自动启用缓存,但是有累加的错误,3.5.9最新版本 #6640

Open
3 tasks done
yang771036958 opened this issue Dec 20, 2024 · 1 comment

Comments

@yang771036958
Copy link

确认

  • 我使用的版本是最新版, 并且使用插件确认过项目里无依赖版本冲突
  • 我已经在 issue 中搜索过, 确认问题没有被提出过
  • 我已经修改标题, 将标题中的 描述 替换为遇到的问题

当前程序版本

3.5.9

问题描述

`package com.fengjun.finance.vo;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fengjun.finance.entity.Enterprise;
import com.fengjun.finance.utils.SnowflakeIdGenerator;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**

  • @classname EnterpriseVO

  • @description TODO

  • @author ywy

  • @Date 2024/10/10 17:43
    */
    @DaTa
    @builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class EnterpriseVO {

    @JsonSerialize(using = ToStringSerializer.class)
    private Long enterpriseId;
    private String enterpriseName;
    private String enterpriseAbbreviationName;

    @JsonSerialize(using = ToStringSerializer.class)
    private Long parentId;
    private Byte archivingStatus;
    private Byte completionStatus;
    private Byte enterpriseType;
    private String mnemonicCode;
    private String taxpayerIdentificationNumber;
    private String enterpriseProvince;
    private String enterpriseCity;

    private Byte businessType;
    private String signatureAnnotator;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @jsonformat(pattern = "yyyy-MM-dd")
    private LocalDate periodWhichBelongsStart;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @jsonformat(pattern = "yyyy-MM-dd")
    private LocalDate periodWhichBelongsEnd;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @jsonformat(pattern = "yyyy-MM-dd")
    private LocalDate reportDate;

    @JsonSerialize(using = ToStringSerializer.class)
    private Long userId;
    private String userName;
    private String nickName;
    private Byte userType;

    /**

    • 企业组
      */
      @JsonSerialize(using = ToStringSerializer.class)
      private Long enterpriseGroup;

    private Integer sort;

    private Boolean isLowestMerge;

    private List users;

    /**

    • 子节点
      */
      private List children = new ArrayList<>();

    /**

    • 科目余额表导入状态,1导入了,2 没导入
      */
      private Integer accountBalanceUploadStatus;

    /**

    • 科目余额表匹配状态1全匹配了,2 没全匹配
      */
      private Integer accountBalanceMatchStatus;

    /**

    • tb的校验状态
      */
      private Integer tbCheck;

    /**

    • @param
    • @return
    • @author ywy
    • @description Enterprise 转换成 EnterpriseVO
    • @Date 2024/10/15 13:44
      */
      public static EnterpriseVO convertToVO(Enterprise enterprise) {
      if (enterprise == null) {
      return null;
      }
      EnterpriseVO vo = new EnterpriseVO();
      vo.setEnterpriseId(enterprise.getId());
      vo.setEnterpriseName(enterprise.getEnterpriseName());
      vo.setEnterpriseAbbreviationName(enterprise.getEnterpriseAbbreviationName());
      vo.setParentId(enterprise.getParentId());
      vo.setArchivingStatus(enterprise.getArchivingStatus());
      vo.setCompletionStatus(enterprise.getCompletionStatus());
      vo.setEnterpriseType(enterprise.getEnterpriseType());
      vo.setMnemonicCode(enterprise.getMnemonicCode());
      vo.setTaxpayerIdentificationNumber(enterprise.getTaxpayerIdentificationNumber());
      vo.setEnterpriseCity(enterprise.getEnterpriseCity());
      vo.setEnterpriseProvince(enterprise.getEnterpriseProvince());
      vo.setReportDate(enterprise.getReportDate());
      vo.setEnterpriseGroup(enterprise.getEnterpriseGroup());
      vo.setPeriodWhichBelongsStart(enterprise.getPeriodWhichBelongsStart());
      vo.setPeriodWhichBelongsEnd(enterprise.getPeriodWhichBelongsEnd());
      vo.setSignatureAnnotator(enterprise.getSignatureAnnotator());
      vo.setReportDate(enterprise.getReportDate());
      vo.setSort(enterprise.getSort());
      return vo;
      }

    /**

    • @param enterpriseVO
    • @return Enterprise
    • @author ywy
    • @description EnterpriseVO 转换成 Enterprise
    • @Date 2024/10/15 13:44
      */
      public static Enterprise convertToVO(EnterpriseVO enterpriseVO) {
      if (enterpriseVO == null) {
      return null;
      }
      Enterprise enterprise = new Enterprise();
      enterprise.setId(enterpriseVO.getEnterpriseId());
      enterprise.setEnterpriseName(enterpriseVO.getEnterpriseName());
      enterprise.setEnterpriseAbbreviationName(enterpriseVO.getEnterpriseAbbreviationName());
      enterprise.setParentId(enterpriseVO.getParentId());
      enterprise.setArchivingStatus(enterpriseVO.getArchivingStatus());
      enterprise.setCompletionStatus(enterpriseVO.getCompletionStatus());
      enterprise.setEnterpriseType(enterpriseVO.getEnterpriseType());
      enterprise.setMnemonicCode(enterpriseVO.getMnemonicCode());
      enterprise.setTaxpayerIdentificationNumber(enterpriseVO.getTaxpayerIdentificationNumber());
      enterprise.setEnterpriseCity(enterpriseVO.getEnterpriseCity());
      enterprise.setEnterpriseProvince(enterpriseVO.getEnterpriseProvince());
      enterprise.setPeriodWhichBelongsStart(enterpriseVO.getPeriodWhichBelongsStart());
      enterprise.setPeriodWhichBelongsEnd(enterpriseVO.getPeriodWhichBelongsEnd());
      enterprise.setSignatureAnnotator(enterpriseVO.getSignatureAnnotator());
      enterprise.setReportDate(enterpriseVO.getReportDate());
      enterprise.setEnterpriseGroup(enterpriseVO.getEnterpriseGroup());
      enterprise.setSort(enterpriseVO.getSort());
      return enterprise;
      }

    private static void buildChildrenTree(EnterpriseVO parent, Map<String, EnterpriseVO> allEnterprise) {
    if (parent.getChildren() == null) {
    parent.setChildren(new ArrayList<>());
    }
    for (EnterpriseVO enterprise : allEnterprise.values()) {
    if (enterprise.getParentId() != null && enterprise.getParentId().equals(parent.getEnterpriseId())) {
    parent.getChildren().add(enterprise);
    // 递归构建当前子节点的子树
    buildChildrenTree(enterprise, allEnterprise);
    }
    }
    }

    private static List getAllChildren(EnterpriseVO parent, Map<String, EnterpriseVO> enterpriseMap) {
    List children = new ArrayList<>();
    if (parent.getChildren() != null) {
    for (EnterpriseVO child : parent.getChildren()) {
    children.add(child);
    // 递归获取当前子节点的所有子节点
    children.addAll(getAllChildren(child, enterpriseMap));
    }
    }
    return children;
    }

    /**

    • @param

    • @return

    • @author ywy

    • @description 获取所有客户的树

    • @Date 2024/11/22 18:22
      */
      public static Map<Long, EnterpriseVO> buildTreeMap(Map<String, EnterpriseVO> allEnterprise) {
      Map<Long, EnterpriseVO> treeMap = new ConcurrentHashMap<>();
      List rootCandidates = new ArrayList<>();

      // 首先,将所有企业对象放入treeMap中,以便后续可以通过ID快速查找
      for (EnterpriseVO enterprise : allEnterprise.values()) {
      treeMap.put(enterprise.getEnterpriseId(), enterprise);
      }

      // 遍历映射中的每个企业对象
      for (EnterpriseVO enterprise : allEnterprise.values()) {
      Long parentId = enterprise.getParentId();
      if (parentId == 0 || parentId == null) {
      // 如果parentId为0或者为null,则视为根节点
      rootCandidates.add(enterprise);
      } else {
      // 否则,将当前企业对象添加到其父节点的子节点列表中
      EnterpriseVO parent = treeMap.get(parentId);
      if (parent != null) {
      parent.getChildren().add(enterprise);
      } else {
      rootCandidates.add(enterprise);
      }
      }
      }
      return treeMap;
      }

    /**

    • @param enterpriseMap

    • @return List

    • @author ywy

    • @description 递归构建树方法,只展示最顶层的客户树

    • @Date 2024/10/11 11:35
      */
      public static List buildTree(Map<String, EnterpriseVO> enterpriseMap) {
      try {
      List rootNodes = new ArrayList<>();
      // 遍历映射中的每个企业对象
      for (EnterpriseVO enterprise : enterpriseMap.values()) {
      String parentId = String.valueOf(enterprise.getParentId());
      if (parentId.equals(0) || !StringUtils.hasText(parentId)) {
      // 如果parentId为null或者父节点不存在于映射中(可能是数据不完整),则视为根节点
      rootNodes.add(enterprise);
      } else {
      // 否则,将当前企业对象添加到其父节点的子节点列表中
      EnterpriseVO parent = enterpriseMap.get(parentId);
      if (parent != null) {
      parent.getChildren().add(enterprise);
      } else {
      rootNodes.add(enterprise);
      }
      }
      }

       // 对根节点进行排序
       rootNodes.sort(Comparator.comparingInt(EnterpriseVO::getSort));
      
       // 对每个根节点的子节点进行排序
       for (EnterpriseVO rootNode : rootNodes) {
           sortChildren(rootNode);
       }
      
       return rootNodes;
      

      } catch (RuntimeException e) {
      throw e;
      } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException("构建客户树发生异常");
      }
      }

    /**

    • @param
    • @return
    • @author ywy
    • @description 构建某个节点下的所有子节点,平铺在同一层级上去
    • @Date 2024/12/19 15:20
      */
      public static List buildList(EnterpriseVO enterpriseVO) {
      List allEnterprises = new ArrayList<>();
      addAllEnterprises(enterpriseVO, allEnterprises);
      return allEnterprises;
      }

    private static void addAllEnterprises(EnterpriseVO enterpriseVO, List allEnterprises) {
    // 首先添加当前节点
    allEnterprises.add(enterpriseVO);

     // 然后递归地添加所有子节点
     List<EnterpriseVO> children = enterpriseVO.getChildren();
     if (children != null) {
         for (EnterpriseVO child : children) {
             addAllEnterprises(child, allEnterprises);
         }
     }
    

    }

    private static void sortChildren(EnterpriseVO node) {
    if (node.getChildren() != null && !node.getChildren().isEmpty()) {
    node.getChildren().sort(Comparator.comparingInt(EnterpriseVO::getSort));
    // 递归地对每个子节点的子节点进行排序
    for (EnterpriseVO child : node.getChildren()) {
    sortChildren(child);
    }
    }
    }

    /**

    • @param enterpriseMap

    • @param topId

    • @return

    • @author ywy

    • @description 从一个企业树结构中复制并生成一个新的企业树结构

    • @Date 2024/10/31 13:34
      */
      public static List copyEnterpriseTreeWithNewParentId(Map<String, EnterpriseVO> enterpriseMap, String topId) {
      SnowflakeIdGenerator idWorker = new SnowflakeIdGenerator(0, 0);
      Map<String, String> oldToNewIdMap = new ConcurrentHashMap<>();
      List copiedTree = new ArrayList<>();

      Long groupId = null;
      // 直接处理顶级客户节点
      EnterpriseVO topEnterprise = enterpriseMap.get(topId);
      if (topEnterprise != null) {
      String newTopId = String.valueOf(idWorker.nextId());
      groupId = Long.valueOf(newTopId);
      oldToNewIdMap.put(topId, newTopId);

       EnterpriseVO copiedTopEnterprise = new EnterpriseVO();
       copiedTopEnterprise.setEnterpriseId(Long.valueOf(newTopId));
       copiedTopEnterprise.setParentId(0L);
       copiedTopEnterprise.setEnterpriseName(topEnterprise.getEnterpriseName());
       copiedTopEnterprise.setTaxpayerIdentificationNumber(topEnterprise.getTaxpayerIdentificationNumber());
       copiedTopEnterprise.setBusinessType(topEnterprise.getBusinessType());
       copiedTopEnterprise.setArchivingStatus(topEnterprise.getArchivingStatus());
       copiedTopEnterprise.setEnterpriseAbbreviationName(topEnterprise.getEnterpriseAbbreviationName());
       copiedTopEnterprise.setSignatureAnnotator(topEnterprise.getSignatureAnnotator());
       copiedTopEnterprise.setReportDate(topEnterprise.getReportDate());
       copiedTopEnterprise.setEnterpriseGroup(groupId);
       copiedTopEnterprise.setSort(topEnterprise.getSort());
       copiedTree.add(copiedTopEnterprise);
      
       // 使用DFS复制子节点
       Deque<String> stack = new ArrayDeque<>();
       stack.addAll(enterpriseMap.keySet().stream()
               .filter(key -> enterpriseMap.get(key).getParentId().equals(topEnterprise.getEnterpriseId()))
               .collect(Collectors.toList()));
      
       while (!stack.isEmpty()) {
           String currentOldId = stack.pop();
           if (!oldToNewIdMap.containsKey(currentOldId)) {
               String currentNewId = String.valueOf(idWorker.nextId());
               oldToNewIdMap.put(currentOldId, currentNewId);
      
               EnterpriseVO currentEnterprise = enterpriseMap.get(currentOldId);
               EnterpriseVO copiedEnterprise = new EnterpriseVO();
               copiedEnterprise.setEnterpriseId(Long.valueOf(currentNewId));
               copiedEnterprise.setParentId(Long.valueOf(oldToNewIdMap.get(String.valueOf(currentEnterprise.getParentId()))));
               copiedEnterprise.setEnterpriseName(currentEnterprise.getEnterpriseName());
               copiedEnterprise.setTaxpayerIdentificationNumber(currentEnterprise.getTaxpayerIdentificationNumber());
               copiedEnterprise.setBusinessType(currentEnterprise.getBusinessType());
               copiedEnterprise.setArchivingStatus(currentEnterprise.getArchivingStatus());
               copiedEnterprise.setEnterpriseAbbreviationName(currentEnterprise.getEnterpriseAbbreviationName());
               copiedEnterprise.setSignatureAnnotator(currentEnterprise.getSignatureAnnotator());
               copiedEnterprise.setReportDate(currentEnterprise.getReportDate());
               copiedEnterprise.setEnterpriseGroup(groupId);
               copiedEnterprise.setSort(currentEnterprise.getSort());
               copiedTree.add(copiedEnterprise);
      
               stack.addAll(enterpriseMap.keySet().stream()
                       .filter(key -> enterpriseMap.get(key).getParentId().equals(currentEnterprise.getEnterpriseId()))
                       .collect(Collectors.toList()));
           }
       }
      

      } else {
      // 处理顶级客户节点不存在的情况
      // 可以抛出异常或返回空列表等
      System.out.println("Top enterprise with ID " + topId + " not found.");
      }

      return copiedTree;
      }

    /**

    • @param
    • @return
    • @author ywy
    • @description 获取所有 children 不为空的节点列表,并按深度排序(最下层的节点在最前面)
    • @Date 2024/11/23 16:58
      */
      public static List getAllNonEmptyChildrenNodesSortedByDepth(EnterpriseVO root) {
      List resultWrappers = new ArrayList<>();
      findNonEmptyChildrenNodes(root, 0, resultWrappers);
      // 根据深度对结果进行排序,深度越大的排在越后面
      Collections.sort(resultWrappers, Comparator.comparingInt(EnterpriseNodeWrapper::getDepth).reversed());
      return resultWrappers;
      }

    private static void findNonEmptyChildrenNodes(EnterpriseVO root, int depth, List result) {
    if (root == null) {
    return;
    }
    // 检查当前节点是否为最低合并节点
    if (root.getChildren().isEmpty()) {
    root.setIsLowestMerge(true);
    } else {
    boolean flag = true;
    for (EnterpriseVO child : root.getChildren()) {
    if (!child.getChildren().isEmpty()) {
    root.setIsLowestMerge(false);
    flag = false;
    break;
    }
    }
    if (flag) {
    root.setIsLowestMerge(flag);
    }
    }

     // 如果当前节点的 children 不为空,则包装并添加到结果列表中
     if (!root.getChildren().isEmpty()) {
         result.add(new EnterpriseNodeWrapper(root, depth));
     }
    
     // 递归遍历所有子节点,深度加1
     for (EnterpriseVO child : root.getChildren()) {
         findNonEmptyChildrenNodes(child, depth + 1, result);
     }
    

    }
    }
    `

` SELECT t1.id, t1.enterprise_name, t1.enterprise_abbreviation_name, t1.parent_id, t1.archiving_status, t1.completion_status, t1.enterprise_type, t1.mnemonic_code, t1.taxpayer_identification_number, t1.enterprise_province, t1.enterprise_city, t1.create_date, t1.update_date, t1.business_type, t1.signature_annotator, t1.period_which_belongs_start, t1.period_which_belongs_end, t1.report_date, t1.enterprise_group, t1.sort, t2.user_id, t2.user_type, t3.user_name, t3.nick_name, t3.mobile FROM enterprise t1 LEFT JOIN enterprise_user t2 ON t1.id = t2.enterprise_id LEFT JOIN user t3 ON t3.id = t2.user_id AND t1.enterprise_id = #{enterpriseVO.enterpriseId} AND t1.enterprise_name LIKE CONCAT('%', #{enterpriseVO.enterpriseName}, '%') AND t1.enterprise_abbreviation_name LIKE CONCAT('%', #{enterpriseVO.enterpriseAbbreviationName}, '%') AND t1.signature_annotator = #{enterpriseVO.signatureAnnotator} AND t1.enterprise_group = #{enterpriseVO.enterpriseGroup} <if test="enterpriseVO.periodWhichBelongsStart != null"> AND t1.period_which_belongs_start &gt;= #{enterpriseVO.periodWhichBelongsStart} <if test="enterpriseVO.periodWhichBelongsEnd != null"> AND </if> </if> <if test="enterpriseVO.periodWhichBelongsEnd != null"> t1.period_which_belongs_end &lt;= #{enterpriseVO.periodWhichBelongsEnd} </if> <if test="enterpriseVO.archivingStatus != null"> t1.archiving_status = #{enterpriseVO.archivingStatus} </if> <if test="enterpriseVO.mnemonicCode != null and enterpriseVO.mnemonicCode != ''"> AND t1.mnemonic_code LIKE CONCAT('%', #{enterpriseVO.mnemonicCode}, '%') </if> <if test="enterpriseVO.businessType != null"> AND t1.business_type = #{enterpriseVO.businessType} </if> <if test="enterpriseVO.parentId != null"> AND t1.parent_id = #{enterpriseVO.parentId} </if> <if test="enterpriseVO.userId != null"> AND t2.user_id = #{enterpriseVO.userId} </if> <if test="enterpriseVO.userName != null and enterpriseVO.userName != ''"> AND t3.user_name LIKE CONCAT('%', #{enterpriseVO.userName}, '%') </if> <if test="enterpriseVO.nickName != null and enterpriseVO.nickName != ''"> AND t3.nick_name LIKE CONCAT('%', #{enterpriseVO.nickName}, '%') </if> </where> ORDER BY t1.enterprise_name ASC,t1.period_which_belongs_end DESC </select>` ` <collection property="users" ofType="com.fengjun.finance.vo.UserVO"> <id property="userId" column="user_id"/> <result property="userName" column="user_name"/> <result property="mobile" column="mobile"/> <result property="nickName" column="nick_name"/> <result property="userType" column="user_type"/> </collection> </resultMap>` controller 请求过来,循环查询相同的条件,会自动启用缓存,但是bean 里面这个 private List children = new ArrayList<>(); 这个属性 一直在累加!这属于bug! xml关掉缓存,正常! 详细堆栈日志 jdk21 虚拟线程

@miemieYaho
Copy link
Member

给出git形式的最小复现demo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants