news 2026/8/14 6:23:55

MP查询的实体有对象嵌套,阿里巴巴的人是怎么处理的

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MP查询的实体有对象嵌套,阿里巴巴的人是怎么处理的

阿里巴巴处理 MP 实体对象嵌套的方案

1. 阿里巴巴推荐的第一方案:DO + DTO 分层

// 1. 数据库实体(DO - Data Object)保持简单@Data@TableName("alarm_config")publicclassAlarmConfigDO{privateLongid;privateStringconfigName;privateLongschemeId;privateIntegerstatus;// ... 其他基础字段}@Data@TableName("alarm_rule")publicclassAlarmRuleDO{privateLongid;privateStringruleName;privateStringruleType;privateDoublethreshold;privateLongconfigId;// 外键,不是对象// ... 其他基础字段}// 2. 业务传输对象(DTO)包含嵌套关系@DatapublicclassAlarmConfigDTO{privateLongid;privateStringconfigName;privateLongschemeId;privateIntegerstatus;// 嵌套对象(不是数据库字段)privateList<AlarmRuleDTO>rules;@DatapublicstaticclassAlarmRuleDTO{privateLongid;privateStringruleName;privateStringruleType;privateDoublethreshold;// 可以包含 config 信息,但不是对象嵌套privateLongconfigId;privateStringconfigName;}}// 3. Service 层组装@ServicepublicclassAlarmConfigService{publicAlarmConfigDTOgetConfigWithRules(LongconfigId){// 分别查询AlarmConfigDOconfigDO=alarmConfigMapper.selectById(configId);List<AlarmRuleDO>ruleDOs=alarmRuleMapper.selectByConfigId(configId);// 手动组装 DTOAlarmConfigDTOdto=convertToDTO(configDO);dto.setRules(ruleDOs.stream().map(this::convertRuleToDTO).collect(Collectors.toList()));returndto;}}

2. 阿里巴巴的 MyBatis 映射方案(XML/注解)

// 方案一:MyBatis XML 映射// AlarmConfigMapper.xml<mapper namespace="com.aiwei.mapper.AlarmConfigMapper"><resultMap id="ConfigWithRulesMap"type="AlarmConfigDTO"><id property="id"column="id"/><result property="configName"column="config_name"/><!--集合映射:一对多--><collection property="rules"ofType="AlarmRuleDTO"select="selectRulesByConfigId"column="id"/></resultMap><select id="selectConfigWithRules"resultMap="ConfigWithRulesMap">SELECT*FROM alarm_configWHEREid=#{configId}</select><select id="selectRulesByConfigId"resultType="AlarmRuleDTO">SELECT*FROM alarm_ruleWHEREconfig_id=#{configId}ANDis_delete=0</select></mapper>// 方案二:注解映射(阿里巴巴较少用,但可用)@MapperpublicinterfaceAlarmConfigMapperextendsBaseMapper<AlarmConfigDO>{@Select("SELECT * FROM alarm_config WHERE id = #{configId}")@Results({@Result(property="id",column="id"),@Result(property="rules",column="id",many=@Many(select="selectRulesByConfigId"))})AlarmConfigDTOselectConfigWithRules(@Param("configId")LongconfigId);@Select("SELECT * FROM alarm_rule WHERE config_id = #{configId}")List<AlarmRuleDTO>selectRulesByConfigId(@Param("configId")LongconfigId);}

3. 阿里巴巴的高性能方案:多表联查 + Map 处理

// 避免 N+1 查询问题,使用 JOIN 一次查完@ServicepublicclassAlarmQueryService{/** * 阿里巴巴推荐:联表查询返回 Map,手动组装 */publicMap<String,Object>getConfigWithRules(LongconfigId){// 1. 联表查询(避免多次查询)List<Map<String,Object>>resultList=alarmConfigMapper.selectConfigWithRulesJoin(configId);// 2. 手动组装为嵌套结构Map<String,Object>configMap=newHashMap<>();List<Map<String,Object>>ruleList=newArrayList<>();if(!resultList.isEmpty()){// 第一条记录包含 config 信息Map<String,Object>firstRow=resultList.get(0);configMap.put("id",firstRow.get("config_id"));configMap.put("name",firstRow.get("config_name"));// 提取所有规则for(Map<String,Object>row:resultList){if(row.get("rule_id")!=null){Map<String,Object>ruleMap=newHashMap<>();ruleMap.put("id",row.get("rule_id"));ruleMap.put("name",row.get("rule_name"));ruleMap.put("type",row.get("rule_type"));ruleMap.put("threshold",row.get("threshold"));ruleList.add(ruleMap);}}}configMap.put("rules",ruleList);returnconfigMap;}}// Mapper SQL@Select("SELECT "+" c.id as config_id, c.config_name, "+" r.id as rule_id, r.rule_name, r.rule_type, r.threshold "+"FROM alarm_config c "+"LEFT JOIN alarm_rule r ON c.id = r.config_id "+"WHERE c.id = #{configId} AND r.is_delete = 0")List<Map<String,Object>>selectConfigWithRulesJoin(@Param("configId")LongconfigId);

4. 阿里巴巴的 COLA 架构模式

// 按照 COLA 架构(Clean Object-oriented & Layered Architecture)// 1. 领域对象(Domain Object)@DatapublicclassAlarmConfig{privateLongid;privateStringname;privateList<AlarmRule>rules;// 领域方法publicvoidaddRule(AlarmRulerule){if(rules==null){rules=newArrayList<>();}rules.add(rule);rule.setConfigId(this.id);}publicbooleanvalidate(){returnrules!=null&&rules.stream().allMatch(AlarmRule::isValid);}}// 2. 数据转换器(Assembler)@ComponentpublicclassAlarmConfigAssembler{publicAlarmConfigtoDomain(AlarmConfigDOconfigDO,List<AlarmRuleDO>ruleDOs){AlarmConfigconfig=newAlarmConfig();config.setId(configDO.getId());config.setName(configDO.getConfigName());// 转换规则List<AlarmRule>rules=ruleDOs.stream().map(this::toRuleDomain).collect(Collectors.toList());config.setRules(rules);returnconfig;}publicAlarmConfigDOtoDO(AlarmConfigconfig){AlarmConfigDOconfigDO=newAlarmConfigDO();configDO.setId(config.getId());configDO.setConfigName(config.getName());returnconfigDO;}}// 3. 仓储层(Repository)@RepositorypublicclassAlarmConfigRepository{@AutowiredprivateAlarmConfigMapperconfigMapper;@AutowiredprivateAlarmRuleMapperruleMapper;@AutowiredprivateAlarmConfigAssemblerassembler;publicAlarmConfigfindById(LongconfigId){// 分别查询AlarmConfigDOconfigDO=configMapper.selectById(configId);List<AlarmRuleDO>ruleDOs=ruleMapper.selectByConfigId(configId);// 组装为领域对象returnassembler.toDomain(configDO,ruleDOs);}}

5. 阿里巴巴的 MapStruct + Builder 模式

// 使用 MapStruct 自动转换@Mapper(componentModel="spring",uses={AlarmRuleMapperConverter.class})publicinterfaceAlarmConfigConverter{AlarmConfigDTOtoDTO(AlarmConfigDOconfigDO);@Mapping(target="rules",ignore=true)AlarmConfigDTOtoSimpleDTO(AlarmConfigDOconfigDO);// 带嵌套的转换defaultAlarmConfigDTOtoDTOWithRules(AlarmConfigDOconfigDO,List<AlarmRuleDO>ruleDOs){AlarmConfigDTOdto=toSimpleDTO(configDO);dto.setRules(ruleDOs.stream().map(AlarmRuleMapperConverter.INSTANCE::toDTO).collect(Collectors.toList()));returndto;}}// Service 使用@Service@RequiredArgsConstructorpublicclassAlarmConfigService{privatefinalAlarmConfigMapperconfigMapper;privatefinalAlarmRuleMapperruleMapper;privatefinalAlarmConfigConverterconverter;publicAlarmConfigDTOgetConfigDetail(LongconfigId){AlarmConfigDOconfigDO=configMapper.selectById(configId);List<AlarmRuleDO>ruleDOs=ruleMapper.selectByConfigId(configId);returnconverter.toDTOWithRules(configDO,ruleDOs);}}

6. 阿里巴巴处理嵌套查询的实际案例

// 案例:告警方案 -> 配置 -> 规则 三级嵌套@ServicepublicclassAlarmSchemeService{/** * 三级嵌套查询的最佳实践 */publicMap<String,Object>getSchemeDetail(LongschemeId){// 1. 查询方案基础信息AlarmSchemeDOscheme=alarmSchemeMapper.selectById(schemeId);// 2. 查询所有配置(避免N+1,批量查询)List<AlarmConfigDO>configs=alarmConfigMapper.selectBySchemeId(schemeId);List<Long>configIds=configs.stream().map(AlarmConfigDO::getId).collect(Collectors.toList());// 3. 批量查询所有规则(一次查询)List<AlarmRuleDO>allRules=alarmRuleMapper.selectByConfigIds(configIds);// 4. 按configId分组规则Map<Long,List<AlarmRuleDO>>rulesByConfigId=allRules.stream().collect(Collectors.groupingBy(AlarmRuleDO::getConfigId));// 5. 组装结果Map<String,Object>result=newLinkedHashMap<>();result.put("scheme",convertScheme(scheme));List<Map<String,Object>>configList=configs.stream().map(config->{Map<String,Object>configMap=convertConfig(config);List<AlarmRuleDO>rules=rulesByConfigId.get(config.getId());if(rules!=null){configMap.put("rules",rules.stream().map(this::convertRule).collect(Collectors.toList()));}returnconfigMap;}).collect(Collectors.toList());result.put("configs",configList);returnresult;}/** * 使用 MP 的 QueryWrapper 进行批量查询 */privateList<AlarmRuleDO>batchQueryRules(List<Long>configIds){if(configIds.isEmpty()){returnCollections.emptyList();}QueryWrapper<AlarmRuleDO>wrapper=newQueryWrapper<>();wrapper.in("config_id",configIds).eq("is_delete",0).eq("status",1).orderByAsc("sort_order");returnalarmRuleMapper.selectList(wrapper);}}

7. 阿里巴巴的缓存方案处理嵌套

// 使用缓存避免重复查询嵌套数据@Service@Slf4jpublicclassCachedAlarmService{@AutowiredprivateRedisTemplate<String,Object>redisTemplate;/** * 阿里巴巴常用:三级缓存策略 */@Cacheable(value="alarm:config:detail",key="#configId",unless="#result == null")publicAlarmConfigDTOgetCachedConfigWithRules(LongconfigId){// 1. 查询配置AlarmConfigDOconfig=alarmConfigMapper.selectById(configId);if(config==null){returnnull;}// 2. 查询规则(使用本地缓存)List<AlarmRuleDO>rules=getCachedRulesByConfigId(configId);// 3. 组装AlarmConfigDTOdto=newAlarmConfigDTO();BeanUtils.copyProperties(config,dto);dto.setRules(rules.stream().map(this::convertRuleToDTO).collect(Collectors.toList()));returndto;}/** * 批量查询规则并缓存 */@Cacheable(value="alarm:rules",key="#configId")publicList<AlarmRuleDO>getCachedRulesByConfigId(LongconfigId){QueryWrapper<AlarmRuleDO>wrapper=newQueryWrapper<>();wrapper.eq("config_id",configId).eq("is_delete",0).orderByAsc("sort_order");returnalarmRuleMapper.selectList(wrapper);}}

8. 阿里巴巴推荐的最佳实践总结

核心原则:

  1. DO 保持简单:数据库实体只包含数据库字段
  2. DTO 承载业务:传输对象包含嵌套关系
  3. 避免 N+1 查询:优先使用 JOIN 或批量查询
  4. 手动组装优于自动映射:更可控,性能更好

具体做法:

// ✅ 阿里巴巴推荐做法:publicAlarmConfigDTOgetConfigDetail(LongconfigId){// 1. 分别查询基础数据AlarmConfigDOconfig=configMapper.selectById(configId);List<AlarmRuleDO>rules=ruleMapper.selectByConfigId(configId);// 2. 手动组装 DTOAlarmConfigDTOdto=newAlarmConfigDTO();BeanUtils.copyProperties(config,dto);// 3. 转换嵌套对象dto.setRules(rules.stream().map(rule->{AlarmRuleDTOruleDto=newAlarmRuleDTO();BeanUtils.copyProperties(rule,ruleDto);returnruleDto;}).collect(Collectors.toList()));returndto;}// ❌ 不推荐做法:// 在 DO 中直接定义对象属性// 依赖 MyBatis 的自动嵌套映射(性能差,难维护)

对于你的告警分析业务:

// 推荐方案:publicMap<String,Object>analyzeAlarm(LongconfigId,LongflightRecordId){// 1. 分别查询AlarmConfigDOconfig=alarmConfigMapper.selectById(configId);List<AlarmRuleDO>rules=alarmRuleMapper.selectEnabledByConfigId(configId);List<FlightDataDO>flightData=flightDataMapper.selectByRecordId(flightRecordId);// 2. 转换为 Map 格式Map<String,List<Map<String,Object>>>ruleMap=rules.stream().collect(Collectors.groupingBy(AlarmRuleDO::getRuleType,Collectors.mapping(this::convertRuleToMap,Collectors.toList())));// 3. 执行业务逻辑Map<String,Object>result=executeAnalysis(ruleMap,flightData);// 4. 组装返回result.put("config",convertConfigToMap(config));result.put("queryTime",LocalDateTime.now());returnresult;}

阿里巴巴内部通常选择:手动组装 + Map 结构,而不是依赖 ORM 的自动嵌套映射。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/11 21:20:40

10分钟极速搭建:transfer.sh私有文件分享系统全攻略

10分钟极速搭建&#xff1a;transfer.sh私有文件分享系统全攻略 【免费下载链接】transfer.sh Easy and fast file sharing from the command-line. 项目地址: https://gitcode.com/gh_mirrors/tr/transfer.sh 还在为临时文件传输而烦恼&#xff1f;邮件附件限制大小、聊…

作者头像 李华
网站建设 2026/8/12 14:37:43

VR青少年法律知识学习系统|VR隔空 “解锁” 法律密码

产品介绍VR 青少年法律知识学习系统&#xff0c;将书籍感应与体感翻书技术相结合。体验者将实体书籍放置感应区&#xff0c;即可触发屏幕显示对应电子书内容&#xff0c;感应设备捕捉手势后&#xff0c;左右挥手便能实现隔空翻阅&#xff1b;同时设有桌面按钮&#xff0c;可切换…

作者头像 李华
网站建设 2026/8/13 15:21:27

coze工作流成品导入一键生成AI漫剧智能体搭建

我用夸克网盘分享了「coze工作流资源库」&#xff0c;点击链接即可保存。打开「夸克APP」&#xff0c;无需下载在线播放视频&#xff0c;畅享原画5倍速&#xff0c;支持电视投屏。 链接&#xff1a;https://pan.quark.cn/s/a0c785412c9a

作者头像 李华
网站建设 2026/8/12 11:06:55

【企业级Docker更新实战指南】:Agent服务无缝升级的5大黄金步骤

第一章&#xff1a;企业级Docker更新的核心挑战在企业级环境中&#xff0c;Docker的持续更新不仅是技术演进的必然要求&#xff0c;更是保障系统安全与性能的关键环节。然而&#xff0c;频繁的版本迭代和复杂的依赖关系使得更新过程充满挑战&#xff0c;尤其是在大规模部署场景…

作者头像 李华