驻马店做网站,seo同行网站,制作校园网站,网站建设 中企动力厨具阿里巴巴处理 MP 实体对象嵌套的方案
1. 阿里巴巴推荐的第一方案#xff1a;DO DTO 分层
// 1. 数据库实体#xff08;DO - Data Object#xff09;保持简单
Data
TableName(alarm_config)
public class AlarmConfigDO {private Long id;private String config…阿里巴巴处理 MP 实体对象嵌套的方案1. 阿里巴巴推荐的第一方案DO DTO 分层// 1. 数据库实体DO - Data Object保持简单DataTableName(alarm_config)publicclassAlarmConfigDO{privateLongid;privateStringconfigName;privateLongschemeId;privateIntegerstatus;// ... 其他基础字段}DataTableName(alarm_rule)publicclassAlarmRuleDO{privateLongid;privateStringruleName;privateStringruleType;privateDoublethreshold;privateLongconfigId;// 外键不是对象// ... 其他基础字段}// 2. 业务传输对象DTO包含嵌套关系DatapublicclassAlarmConfigDTO{privateLongid;privateStringconfigName;privateLongschemeId;privateIntegerstatus;// 嵌套对象不是数据库字段privateListAlarmRuleDTOrules;DatapublicstaticclassAlarmRuleDTO{privateLongid;privateStringruleName;privateStringruleType;privateDoublethreshold;// 可以包含 config 信息但不是对象嵌套privateLongconfigId;privateStringconfigName;}}// 3. Service 层组装ServicepublicclassAlarmConfigService{publicAlarmConfigDTOgetConfigWithRules(LongconfigId){// 分别查询AlarmConfigDOconfigDOalarmConfigMapper.selectById(configId);ListAlarmRuleDOruleDOsalarmRuleMapper.selectByConfigId(configId);// 手动组装 DTOAlarmConfigDTOdtoconvertToDTO(configDO);dto.setRules(ruleDOs.stream().map(this::convertRuleToDTO).collect(Collectors.toList()));returndto;}}2. 阿里巴巴的 MyBatis 映射方案XML/注解// 方案一MyBatis XML 映射// AlarmConfigMapper.xmlmapper namespacecom.aiwei.mapper.AlarmConfigMapperresultMap idConfigWithRulesMaptypeAlarmConfigDTOid propertyidcolumnid/result propertyconfigNamecolumnconfig_name/!--集合映射一对多--collection propertyrulesofTypeAlarmRuleDTOselectselectRulesByConfigIdcolumnid//resultMapselect idselectConfigWithRulesresultMapConfigWithRulesMapSELECT*FROM alarm_configWHEREid#{configId}/selectselect idselectRulesByConfigIdresultTypeAlarmRuleDTOSELECT*FROM alarm_ruleWHEREconfig_id#{configId}ANDis_delete0/select/mapper// 方案二注解映射阿里巴巴较少用但可用MapperpublicinterfaceAlarmConfigMapperextendsBaseMapperAlarmConfigDO{Select(SELECT * FROM alarm_config WHERE id #{configId})Results({Result(propertyid,columnid),Result(propertyrules,columnid,manyMany(selectselectRulesByConfigId))})AlarmConfigDTOselectConfigWithRules(Param(configId)LongconfigId);Select(SELECT * FROM alarm_rule WHERE config_id #{configId})ListAlarmRuleDTOselectRulesByConfigId(Param(configId)LongconfigId);}3. 阿里巴巴的高性能方案多表联查 Map 处理// 避免 N1 查询问题使用 JOIN 一次查完ServicepublicclassAlarmQueryService{/** * 阿里巴巴推荐联表查询返回 Map手动组装 */publicMapString,ObjectgetConfigWithRules(LongconfigId){// 1. 联表查询避免多次查询ListMapString,ObjectresultListalarmConfigMapper.selectConfigWithRulesJoin(configId);// 2. 手动组装为嵌套结构MapString,ObjectconfigMapnewHashMap();ListMapString,ObjectruleListnewArrayList();if(!resultList.isEmpty()){// 第一条记录包含 config 信息MapString,ObjectfirstRowresultList.get(0);configMap.put(id,firstRow.get(config_id));configMap.put(name,firstRow.get(config_name));// 提取所有规则for(MapString,Objectrow:resultList){if(row.get(rule_id)!null){MapString,ObjectruleMapnewHashMap();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 SQLSelect(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)ListMapString,ObjectselectConfigWithRulesJoin(Param(configId)LongconfigId);4. 阿里巴巴的 COLA 架构模式// 按照 COLA 架构Clean Object-oriented Layered Architecture// 1. 领域对象Domain ObjectDatapublicclassAlarmConfig{privateLongid;privateStringname;privateListAlarmRulerules;// 领域方法publicvoidaddRule(AlarmRulerule){if(rulesnull){rulesnewArrayList();}rules.add(rule);rule.setConfigId(this.id);}publicbooleanvalidate(){returnrules!nullrules.stream().allMatch(AlarmRule::isValid);}}// 2. 数据转换器AssemblerComponentpublicclassAlarmConfigAssembler{publicAlarmConfigtoDomain(AlarmConfigDOconfigDO,ListAlarmRuleDOruleDOs){AlarmConfigconfignewAlarmConfig();config.setId(configDO.getId());config.setName(configDO.getConfigName());// 转换规则ListAlarmRulerulesruleDOs.stream().map(this::toRuleDomain).collect(Collectors.toList());config.setRules(rules);returnconfig;}publicAlarmConfigDOtoDO(AlarmConfigconfig){AlarmConfigDOconfigDOnewAlarmConfigDO();configDO.setId(config.getId());configDO.setConfigName(config.getName());returnconfigDO;}}// 3. 仓储层RepositoryRepositorypublicclassAlarmConfigRepository{AutowiredprivateAlarmConfigMapperconfigMapper;AutowiredprivateAlarmRuleMapperruleMapper;AutowiredprivateAlarmConfigAssemblerassembler;publicAlarmConfigfindById(LongconfigId){// 分别查询AlarmConfigDOconfigDOconfigMapper.selectById(configId);ListAlarmRuleDOruleDOsruleMapper.selectByConfigId(configId);// 组装为领域对象returnassembler.toDomain(configDO,ruleDOs);}}5. 阿里巴巴的 MapStruct Builder 模式// 使用 MapStruct 自动转换Mapper(componentModelspring,uses{AlarmRuleMapperConverter.class})publicinterfaceAlarmConfigConverter{AlarmConfigDTOtoDTO(AlarmConfigDOconfigDO);Mapping(targetrules,ignoretrue)AlarmConfigDTOtoSimpleDTO(AlarmConfigDOconfigDO);// 带嵌套的转换defaultAlarmConfigDTOtoDTOWithRules(AlarmConfigDOconfigDO,ListAlarmRuleDOruleDOs){AlarmConfigDTOdtotoSimpleDTO(configDO);dto.setRules(ruleDOs.stream().map(AlarmRuleMapperConverter.INSTANCE::toDTO).collect(Collectors.toList()));returndto;}}// Service 使用ServiceRequiredArgsConstructorpublicclassAlarmConfigService{privatefinalAlarmConfigMapperconfigMapper;privatefinalAlarmRuleMapperruleMapper;privatefinalAlarmConfigConverterconverter;publicAlarmConfigDTOgetConfigDetail(LongconfigId){AlarmConfigDOconfigDOconfigMapper.selectById(configId);ListAlarmRuleDOruleDOsruleMapper.selectByConfigId(configId);returnconverter.toDTOWithRules(configDO,ruleDOs);}}6. 阿里巴巴处理嵌套查询的实际案例// 案例告警方案 - 配置 - 规则 三级嵌套ServicepublicclassAlarmSchemeService{/** * 三级嵌套查询的最佳实践 */publicMapString,ObjectgetSchemeDetail(LongschemeId){// 1. 查询方案基础信息AlarmSchemeDOschemealarmSchemeMapper.selectById(schemeId);// 2. 查询所有配置避免N1批量查询ListAlarmConfigDOconfigsalarmConfigMapper.selectBySchemeId(schemeId);ListLongconfigIdsconfigs.stream().map(AlarmConfigDO::getId).collect(Collectors.toList());// 3. 批量查询所有规则一次查询ListAlarmRuleDOallRulesalarmRuleMapper.selectByConfigIds(configIds);// 4. 按configId分组规则MapLong,ListAlarmRuleDOrulesByConfigIdallRules.stream().collect(Collectors.groupingBy(AlarmRuleDO::getConfigId));// 5. 组装结果MapString,ObjectresultnewLinkedHashMap();result.put(scheme,convertScheme(scheme));ListMapString,ObjectconfigListconfigs.stream().map(config-{MapString,ObjectconfigMapconvertConfig(config);ListAlarmRuleDOrulesrulesByConfigId.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 进行批量查询 */privateListAlarmRuleDObatchQueryRules(ListLongconfigIds){if(configIds.isEmpty()){returnCollections.emptyList();}QueryWrapperAlarmRuleDOwrappernewQueryWrapper();wrapper.in(config_id,configIds).eq(is_delete,0).eq(status,1).orderByAsc(sort_order);returnalarmRuleMapper.selectList(wrapper);}}7. 阿里巴巴的缓存方案处理嵌套// 使用缓存避免重复查询嵌套数据ServiceSlf4jpublicclassCachedAlarmService{AutowiredprivateRedisTemplateString,ObjectredisTemplate;/** * 阿里巴巴常用三级缓存策略 */Cacheable(valuealarm:config:detail,key#configId,unless#result null)publicAlarmConfigDTOgetCachedConfigWithRules(LongconfigId){// 1. 查询配置AlarmConfigDOconfigalarmConfigMapper.selectById(configId);if(confignull){returnnull;}// 2. 查询规则使用本地缓存ListAlarmRuleDOrulesgetCachedRulesByConfigId(configId);// 3. 组装AlarmConfigDTOdtonewAlarmConfigDTO();BeanUtils.copyProperties(config,dto);dto.setRules(rules.stream().map(this::convertRuleToDTO).collect(Collectors.toList()));returndto;}/** * 批量查询规则并缓存 */Cacheable(valuealarm:rules,key#configId)publicListAlarmRuleDOgetCachedRulesByConfigId(LongconfigId){QueryWrapperAlarmRuleDOwrappernewQueryWrapper();wrapper.eq(config_id,configId).eq(is_delete,0).orderByAsc(sort_order);returnalarmRuleMapper.selectList(wrapper);}}8. 阿里巴巴推荐的最佳实践总结核心原则DO 保持简单数据库实体只包含数据库字段DTO 承载业务传输对象包含嵌套关系避免 N1 查询优先使用 JOIN 或批量查询手动组装优于自动映射更可控性能更好具体做法// ✅ 阿里巴巴推荐做法publicAlarmConfigDTOgetConfigDetail(LongconfigId){// 1. 分别查询基础数据AlarmConfigDOconfigconfigMapper.selectById(configId);ListAlarmRuleDOrulesruleMapper.selectByConfigId(configId);// 2. 手动组装 DTOAlarmConfigDTOdtonewAlarmConfigDTO();BeanUtils.copyProperties(config,dto);// 3. 转换嵌套对象dto.setRules(rules.stream().map(rule-{AlarmRuleDTOruleDtonewAlarmRuleDTO();BeanUtils.copyProperties(rule,ruleDto);returnruleDto;}).collect(Collectors.toList()));returndto;}// ❌ 不推荐做法// 在 DO 中直接定义对象属性// 依赖 MyBatis 的自动嵌套映射性能差难维护对于你的告警分析业务// 推荐方案publicMapString,ObjectanalyzeAlarm(LongconfigId,LongflightRecordId){// 1. 分别查询AlarmConfigDOconfigalarmConfigMapper.selectById(configId);ListAlarmRuleDOrulesalarmRuleMapper.selectEnabledByConfigId(configId);ListFlightDataDOflightDataflightDataMapper.selectByRecordId(flightRecordId);// 2. 转换为 Map 格式MapString,ListMapString,ObjectruleMaprules.stream().collect(Collectors.groupingBy(AlarmRuleDO::getRuleType,Collectors.mapping(this::convertRuleToMap,Collectors.toList())));// 3. 执行业务逻辑MapString,ObjectresultexecuteAnalysis(ruleMap,flightData);// 4. 组装返回result.put(config,convertConfigToMap(config));result.put(queryTime,LocalDateTime.now());returnresult;}阿里巴巴内部通常选择手动组装 Map 结构而不是依赖 ORM 的自动嵌套映射。