You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Node/Express/SQL Server分页开发:获取总条数及当前页数据报错求助

我来帮你搞定这个分页问题!在Node/Express+SQL Server环境下做分页,确实需要同时拿到不受分页影响的总数据行数当前页数据,但两个查询的写法有不少容易踩的坑,尤其是异步处理和连接池复用这块,很容易导致报错或者请求挂起。

核心思路与正确实现

你提到的“写两个查询”是可行的,但要注意异步流程的控制和连接池的正确使用;另外还有更高效的方式——用SQL Server的窗口函数一次查询搞定,减少数据库请求次数。下面分别给出两种方案的正确代码:


方案1:两个独立查询(先查总条数,再查分页数据)

这种方式逻辑清晰,但需要注意用async/await处理异步,避免回调地狱,同时复用连接池(不要每次请求新建连接池):

const sql = require('mssql');
const config = require('./your-config-path'); // 替换成你的数据库配置文件路径

// 全局初始化连接池,不要每次请求新建
const pool = new sql.ConnectionPool(config);
pool.connect().catch(err => console.error('连接池初始化失败:', err));

router.get('/', async (req, res) => {
  try {
    // 解析分页参数,默认第一页,每页10条
    const { page = 1, pageSize = 10 } = req.query;
    const offset = (parseInt(page) - 1) * parseInt(pageSize);

    // 1. 查询总数据条数
    const countQueryResult = await pool.request().query('SELECT COUNT(*) AS totalCount FROM YourTableName');
    const totalCount = countQueryResult.recordset[0].totalCount;

    // 2. 查询当前页数据(注意必须加ORDER BY,否则OFFSET结果不确定)
    const dataQueryResult = await pool.request()
      .input('offset', sql.Int, offset)
      .input('pageSize', sql.Int, parseInt(pageSize))
      .query(`
        SELECT * FROM YourTableName 
        ORDER BY id  -- 替换成你需要的排序字段
        OFFSET @offset ROWS FETCH NEXT @pageSize ROWS ONLY
      `);
    const pageData = dataQueryResult.recordset;

    // 设置分页响应头(可选,方便前端获取分页信息)
    res.set('X-Total-Count', totalCount);
    res.set('X-Current-Page', page);
    res.set('X-Page-Size', pageSize);

    // 返回最终响应
    res.json({
      totalCount,
      currentPage: parseInt(page),
      pageSize: parseInt(pageSize),
      data: pageData
    });
  } catch (err) {
    console.error('分页查询失败:', err);
    res.status(500).json({ error: '服务器内部错误', details: err.message });
  }
});

方案2:用窗口函数一次查询(更高效)

COUNT(*) OVER()窗口函数可以在查询分页数据的同时,直接拿到总条数,只需要一次数据库请求:

router.get('/', async (req, res) => {
  try {
    const { page = 1, pageSize = 10 } = req.query;
    const offset = (parseInt(page) - 1) * parseInt(pageSize);

    const queryResult = await pool.request()
      .input('offset', sql.Int, offset)
      .input('pageSize', sql.Int, parseInt(pageSize))
      .query(`
        SELECT *, COUNT(*) OVER() AS totalCount 
        FROM YourTableName 
        ORDER BY id 
        OFFSET @offset ROWS FETCH NEXT @pageSize ROWS ONLY
      `);

    const pageData = queryResult.recordset;
    // 总条数取第一条数据的totalCount即可(如果没有数据则为0)
    const totalCount = pageData.length > 0 ? pageData[0].totalCount : 0;

    // 响应头和返回数据处理
    res.set('X-Total-Count', totalCount);
    res.set('X-Current-Page', page);
    res.set('X-Page-Size', pageSize);

    res.json({
      totalCount,
      currentPage: parseInt(page),
      pageSize: parseInt(pageSize),
      data: pageData.map(item => {
        // 移除返回数据中的totalCount字段,只保留业务数据
        const { totalCount, ...businessData } = item;
        return businessData;
      })
    });
  } catch (err) {
    console.error('分页查询失败:', err);
    res.status(500).json({ error: '服务器内部错误', details: err.message });
  }
});

你原来代码可能报错的原因

  1. 异步流程混乱:没有用async/await或正确的回调嵌套,导致还没拿到查询结果就尝试发送响应,或者请求挂起;
  2. 连接池使用错误:每次请求新建sql.ConnectionPool,但没等连接成功就执行查询,导致连接失败;
  3. SQL语法问题OFFSET/FETCH是SQL Server 2012及以上版本才支持的语法,或者没有加ORDER BY(必须加,否则分页结果无意义);
  4. 参数未校验:前端传的pagepageSize是字符串,直接拼接进SQL会导致语法错误,建议转成数字后用参数化查询(上面的代码已经做了处理)。

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

火山引擎 最新活动