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

Spring Boot优化百万级数据查询:解决Ajax超时及分页异常

问题概述
  • Ajax获取数据耗时极长,半小时后触发会话超时,需实现1秒内获取10万条数据的能力
  • 数据每日递增,1年后将达40万条,现有全量查询方式无法支撑
  • 已实现Ajax分页,但优化查询后仅能返回单条数据

一、优化查询耗时,支撑大数据量场景

1. 数据库层面优化

  • 添加联合索引:针对查询条件num_isvalid和排序字段alumni_user_id创建索引,避免全表扫描
    CREATE INDEX idx_valid_id ON sis.nvs_alumni_registration(num_isvalid, alumni_user_id DESC);
    
  • 替换N+1查询:原代码中jnvNmae字段通过循环调用globalFunction.getInstNameByInstId获取,改成SQL关联查询直接返回名称,消除循环调用开销
    修改DAO层SQL(假设机构表为sis.institution,关联字段为jnv_name对应inst_id):
    SELECT 
        a.alumni_user_id, a.alumni_name, a.alumni_login_id, a.year_of_passing, 
        inst.inst_name AS jnv_name,
        a.fields_of_work_id, a.country_name, a.alumni_email, a.contact_no, 
        a.class_passng_jnv, a.isnri, a.status_of_working, a.present_qualification, 
        a.present_organisation, a.present_designation 
    FROM sis.nvs_alumni_registration a
    LEFT JOIN sis.institution inst ON a.jnv_name = inst.inst_id
    WHERE a.num_isvalid='1' 
    ORDER BY a.alumni_user_id DESC 
    LIMIT ? OFFSET ?;
    
  • 强制分页查询:彻底放弃全量拉取数据,通过LIMIT+OFFSET控制单次返回数据量,适配前端分页需求

2. 代码层面优化

  • Controller接收分页参数:新增page和size参数,校验会话合法性后传递到业务层
    @RequestMapping(value = "/showReportforDirectory", method = RequestMethod.GET)
    public @ResponseBody List<AlumniBeanForDirectory> showReport(HttpServletRequest request, 
                                                                 @RequestParam(defaultValue = "1") Integer page,
                                                                 @RequestParam(defaultValue = "20") Integer size) {
        HttpSession session = request.getSession(false);
        if (session == null || session.getAttribute("isuseractive") == null || session.getAttribute("isuseractive").equals("")) {
            return Collections.emptyList();
        }
        try {
            return alumniService.getAlumniRegDetailsByPage(page, size);
        } catch (Exception e) {
            e.printStackTrace();
            return Collections.emptyList();
        }
    }
    
  • Service层处理分页逻辑:计算偏移量,调用DAO的分页查询方法,过滤转换失败的null对象
    @Override
    public List<AlumniBeanForDirectory> getAlumniRegDetailsByPage(Integer page, Integer size) {
        int offset = (page - 1) * size;
        return emptyIfNull(alumniDaoImpl.getAlumniRegistrationDetailsByPage(size, offset))
                .stream()
                .map(this::setAlumniDirectoryToBean)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
    
  • DAO层执行分页SQL:传递分页参数,确保SQL正确接收size和offset
    public List<Object[]> getAlumniRegistrationDetailsByPage(Integer size, Integer offset) {
        try {
            String query = "SELECT ... -- 上面修改后的关联SQL"
                    + " LIMIT ? OFFSET ?";
            return dataAccess.runNative(query, size, offset); // 确保runNative支持参数绑定
        } catch (Exception e) {
            e.printStackTrace();
            return Collections.emptyList();
        }
    }
    
  • 修复Bean转换错误:将(obj[10]).toString()=="0"改为"0".equals(obj[10].toString()),避免字符串比较错误;同时确保转换异常时返回的null被过滤,不影响列表数据

二、解决会话超时问题

  • 控制单次请求数据量:通过分页每次返回20-50条数据,大幅缩短请求耗时,避免会话超时
  • 调整会话超时配置:在application.properties中适当延长会话超时(仅作为辅助方案,优先通过分页解决)
    server.servlet.session.timeout=30m
    
  • 异步请求处理:若需批量获取数据,改用异步请求避免阻塞HTTP会话,Controller添加@Async注解,返回CompletableFuture<List<AlumniBeanForDirectory>>,前端配合异步接收

三、修复分页仅返回单条数据问题

  • 校验分页参数传递:确认前端传递的page和size参数正确到达后端,避免参数缺失导致默认LIMIT 1
  • 检查DAO参数绑定:确认runNative方法正确处理参数顺序,避免将offset当成size传入
  • 直接验证SQL:在数据库客户端执行分页SQL,检查返回结果是否符合预期,排除SQL语法错误

内容的提问来源于stack exchange,提问作者Megha Tyagi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 06:54:59