You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring WebFlux + MongoDB 查询300条Ticket数据耗时25秒求助

优化思路与解决方案

1. 优化对象转换性能

你当前在getAllTickets中使用ObjectMapper逐个反射转换TicketData到Ticket,这是高频性能损耗点:

  • 启用Jackson的快速解析/写入优化:
    ObjectMapper mapper = new ObjectMapper()
        .enable(MapperFeature.USE_FAST_JSONPARSER)
        .enable(MapperFeature.USE_FAST_BEAN_PROPERTY_WRITER);
    
  • 替换为MapStruct(编译期生成转换代码,性能远高于反射):
    先定义映射接口:
    @Mapper(componentModel = "spring")
    public interface TicketMapper {
        Ticket map(TicketData ticketData);
        List<Ticket> map(List<TicketData> ticketDataList);
    }
    
    之后在适配器中注入TicketMapper,替换原有的ObjectMapper转换逻辑:
    @Override
    public Flux<Ticket> getAllTickets() {
        return this.ticketRepository
                .findAll()
                .buffer(50) // 批量减少转换次数
                .flatMap(buffer -> Flux.fromIterable(ticketMapper.map(buffer)));
    }
    

2. 排查MongoDB事件监听器开销

日志显示onAfterLoad和onAfterConvert执行缓慢,需检查:

  • 项目中是否存在自定义MongoEventListener?如果有,移除监听器中不必要的耗时操作(如额外DB查询、复杂计算),或直接删除无用监听器。
  • 禁用Spring Data MongoDB默认事件处理(若无需监听):
    在application.yml中添加配置:
    spring:
      data:
        mongodb:
          event:
            enabled: false
    

3. 优化响应式流处理逻辑

  • 用buffer()批量处理文档,减少单条数据转换的上下文切换开销,示例代码见上述MapStruct部分。
  • 避免在map操作中执行阻塞逻辑,确保所有转换操作都是非阻塞的。

4. 检查MongoDB序列化配置

  • 自定义LocalDateTime的序列化/反序列化逻辑,替换默认的日期转换(默认实现可能存在额外性能损耗):
    @Configuration
    public class MongoConfig {
        @Bean
        public MongoCustomConversions mongoCustomConversions() {
            List<Converter<?, ?>> converters = new ArrayList<>();
            converters.add(new LocalDateTimeToDateConverter());
            converters.add(new DateToLocalDateTimeConverter());
            return new MongoCustomConversions(converters);
        }
    
        @WritingConverter
        static class LocalDateTimeToDateConverter implements Converter<LocalDateTime, Date> {
            @Override
            public Date convert(LocalDateTime source) {
                return source == null ? null : Date.from(source.atZone(ZoneId.systemDefault()).toInstant());
            }
        }
    
        @ReadingConverter
        static class DateToLocalDateTimeConverter implements Converter<Date, LocalDateTime> {
            @Override
            public LocalDateTime convert(Date source) {
                return source == null ? null : LocalDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
            }
        }
    }
    

5. 验证查询阶段耗时

用MongoDB的执行计划确认是否是查询本身的问题:
在Repository中添加方法:

@Query(value = "{}")
Flux<TicketData> findAllWithExplain();

执行后查看执行计划,确认查询阶段的实际耗时,排除数据库查询本身的性能问题。

内容的提问来源于stack exchange,提问作者Julián Rojas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 14:22:49