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

使用npm mssql包查询SQL Server出现缓存问题求助

问题

使用npm的mssql包从SQL Server获取数据,尽管数据库中的数据已更新,但每次通过Postman发起请求时,都得到相同的结果集。

连接配置及代码如下:

const sql = require('mssql');
const config = {
  user: 'XXXX',
  password: 'XXXX',
  server: 'XXXX',
  database: 'XXXX',
  pool: {
    max: 50,
    min: 0,
    idleTimeoutMillis: 10
  },
  options: {
    trustServerCertificate: true
  }
}

const getConnection = async () => {
  try {
    const conn = await sql.connect(config);
    return {pool: conn, err: false, errorMSG: null};
  } catch (err) {
    return {conn: null, err: true, errorMSG: err}
  }
};

数据库操作函数:

const conn = await getConnection();

if (conn.err == false) {
  try {
    let result = await conn.pool.request()
      .input('registryNumber', sql.NVarChar(50), registryNumber)
      .input('password', sql.NVarChar(50), password)
      .query('SELECT role FROM [OperatorLogin].[dbo].[TBL_users]' +
        'WHERE [TBL_users].[registryNumber] = @registryNumber AND [TBL_users].[password] = @password AND [TBL_users].[isActive] = 1 ')
    if (result.rowsAffected[0] >= 1) {
      return { Execution: true, ExecutionCode: 1, ExecutionMessage: "Record is available", ExecutionData: result.recordset }
    } else {
      return { Execution: true, ExecutionCode: 2, ExecutionMessage: "No records", ExecutionData: "" }
    }
  } catch (err) {
    return { Execution: false, ExecutionCode: -1, ExecutionMessage: "DB pool request error : " + err, ExecutionData: "" }
  }
} else {
  return { Execution: false, ExecutionCode: -1, ExecutionMessage: " DB error : " + conn.errorMSG, ExecutionData: "" }
}

服务器环境:Windows服务器,使用pm2和反向代理。请问可能是什么问题?忽略了哪些要点?

排查方向与解决方案
  • 连接池与事务隔离级别问题
    mssql的sql.connect()是全局单例模式,多次调用会复用同一个连接池。如果连接池中的连接处于REPEATABLE READ等隔离级别,会导致同一连接重复读取同一数据快照。
    解决:

    1. 查询时显式设置隔离级别为READ COMMITTED:
      await conn.pool.request()
        .query('SET TRANSACTION ISOLATION LEVEL READ COMMITTED')
        .input('registryNumber', sql.NVarChar(50), registryNumber)
        .input('password', sql.NVarChar(50), password)
        .query('SELECT role FROM [OperatorLogin].[dbo].[TBL_users] WHERE ...')
      
    2. 开启数据库的READ_COMMITTED_SNAPSHOT选项:
      ALTER DATABASE [OperatorLogin] SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;
      
  • 反向代理缓存
    反向代理(如Nginx、IIS)可能对API请求结果开启了静态缓存,导致返回旧数据。
    解决:

    1. 对动态API接口添加禁用缓存的响应头:
      Cache-Control: no-cache, no-store, must-revalidate
      Pragma: no-cache
      Expires: 0
      
    2. 直接访问应用端口(绕过反向代理)测试,确认是否为代理缓存问题。
  • PM2进程内存缓存
    如果代码中存在全局变量缓存查询结果(如将查询结果存在模块级变量中),PM2启动的进程会一直复用旧数据,直到进程重启。
    解决:

    1. 检查代码逻辑,确保每次请求都重新执行数据库查询,不依赖全局缓存。
    2. 执行pm2 restart <应用名称>重启进程,验证是否恢复正常。
  • 数据库更新未提交
    确认数据库中的数据更新操作是否已提交事务。如果在SSMS等工具中修改数据后未执行COMMIT,其他连接将无法看到更新。
    解决:修改数据后执行COMMIT语句,或开启工具的自动提交功能。

  • 连接池配置不合理
    配置中idleTimeoutMillis: 10过小,会导致连接频繁销毁重建,也可能因连接复用逻辑异常读取旧数据;且每次请求都调用sql.connect()会重复初始化连接池。
    解决:

    1. 将idleTimeoutMillis调整为合理值(如30000,即30秒)。
    2. 应用启动时仅初始化一次连接池,后续操作直接复用:
      // 应用启动阶段初始化
      let pool;
      const initPool = async () => {
        pool = await sql.connect(config);
      };
      initPool();
      
      // 数据库操作时直接使用pool
      const result = await pool.request()
        .input('registryNumber', sql.NVarChar(50), registryNumber)
        .input('password', sql.NVarChar(50), password)
        .query('SELECT role FROM [OperatorLogin].[dbo].[TBL_users] WHERE ...')
      

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 00:45:40