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

如何循环执行SELECT语句实现Oracle数据库数据实时更新?

解决Oracle数据库更新后Express服务无法实时获取新数据的问题

原代码的核心问题

原服务启动时仅执行一次SQL查询,将结果缓存到内存后就不再更新,后续所有/teste请求都返回这组旧数据,自然无法感知数据库的实时变化。

方案1:每次请求时重新查询(最直接)

将查询逻辑嵌入路由处理函数,每次收到请求都重新执行SQL,确保返回最新数据。同时用连接池管理数据库连接,避免频繁创建/销毁连接的性能损耗:

const express = require('express');
const oracledb = require('oracledb');
const app = express();
const cors = require('cors');
app.use(cors());

// 数据库连接配置
const dbConfig = {
  user: 'sapiensproducao',
  password: 'fabrica',
  connectionString: 'dbprod'
};

// 初始化数据库连接池
async function initPool() {
  try {
    await oracledb.createPool(dbConfig);
    console.log('数据库连接池初始化成功');
  } catch (err) {
    console.error('连接池初始化失败:', err.message);
    process.exit(1);
  }
}

// 路由:每次请求都查询最新数据
app.get('/teste', async (req, res) => {
  let connection;
  try {
    connection = await oracledb.getConnection();
    const query = `SELECT CODEMP,CODORI,NUMORP,SEQEOQ,DATREA,HORREA,CODPRO,CODDER,QTDRE1,QTDRFG,CODLOT,OBSEOQ 
                   FROM USU_VPROEXT 
                   ORDER BY DATREA DESC, HORREA DESC`;
    const result = await connection.execute(query);
    res.json(result.rows);
  } catch (err) {
    console.error('查询失败:', err.message);
    res.status(500).json({ error: '查询数据库失败' });
  } finally {
    if (connection) {
      try {
        await connection.close(); // 释放连接回池
      } catch (err) {
        console.error('关闭连接失败:', err.message);
      }
    }
  }
});

// 先初始化连接池再启动服务
initPool().then(() => {
  app.listen(3000, () => {
    console.log('服务监听在端口3000');
  });
});

方案2:定时轮询缓存结果(适合高请求频率场景)

如果请求频率高,每次查库会造成性能压力,可用setInterval定时执行查询,将结果缓存到变量中,路由直接返回缓存数据:

const express = require('express');
const oracledb = require('oracledb');
const app = express();
const cors = require('cors');
app.use(cors());

const dbConfig = {
  user: 'sapiensproducao',
  password: 'fabrica',
  connectionString: 'dbprod'
};

let cachedData = []; // 存储最新查询结果

// 查询数据库并更新缓存
async function updateCachedData() {
  let connection;
  try {
    connection = await oracledb.getConnection(dbConfig);
    const query = `SELECT CODEMP,CODORI,NUMORP,SEQEOQ,DATREA,HORREA,CODPRO,CODDER,QTDRE1,QTDRFG,CODLOT,OBSEOQ 
                   FROM USU_VPROEXT 
                   ORDER BY DATREA DESC, HORREA DESC`;
    const result = await connection.execute(query);
    cachedData = result.rows;
    console.log(`缓存已更新,共${cachedData.length}条数据`);
  } catch (err) {
    console.error('更新缓存失败:', err.message);
  } finally {
    if (connection) {
      try {
        await connection.close();
      } catch (err) {
        console.error('关闭连接失败:', err.message);
      }
    }
  }
}

// 初始化缓存,之后每30秒更新一次(可根据业务调整间隔)
updateCachedData();
setInterval(updateCachedData, 30000);

// 路由返回缓存数据
app.get('/teste', (req, res) => {
  res.json(cachedData);
});

app.listen(3000, () => {
  console.log('服务监听在端口3000');
});

方案3:Oracle数据库变更通知(实时感知更新)

如果需要实时感知数据库变化,可使用Oracle的变更通知功能,当目标表数据变更时自动触发缓存更新。此方案需数据库端配置权限,实现复杂度较高:

const express = require('express');
const oracledb = require('oracledb');
const app = express();
const cors = require('cors');
app.use(cors());

const dbConfig = {
  user: 'sapiensproducao',
  password: 'fabrica',
  connectionString: 'dbprod'
};

let cachedData = [];

async function initChangeNotification() {
  const connection = await oracledb.getConnection(dbConfig);
  const query = `SELECT CODEMP,CODORI,NUMORP,SEQEOQ,DATREA,HORREA,CODPRO,CODDER,QTDRE1,QTDRFG,CODLOT,OBSEOQ 
                 FROM USU_VPROEXT 
                 ORDER BY DATREA DESC, HORREA DESC`;

  // 注册变更通知
  await connection.subscribe(
    'USU_VPROEXT_CHANGE',
    {
      sql: query,
      callback: async () => {
        console.log('检测到数据库变更,更新缓存');
        const result = await connection.execute(query);
        cachedData = result.rows;
      },
      timeout: 0 // 永久监听
    }
  );
  console.log('变更通知已注册');

  // 初始化缓存
  const result = await connection.execute(query);
  cachedData = result.rows;
}

app.get('/teste', (req, res) => {
  res.json(cachedData);
});

initChangeNotification().then(() => {
  app.listen(3000, () => {
    console.log('服务监听在端口3000');
  });
}).catch(err => {
  console.error('初始化变更通知失败:', err.message);
  process.exit(1);
});

方案选择建议

  • 方案1:适合请求量小、对数据新鲜度要求极高的场景,每次请求都能拿到绝对最新数据,但数据库压力稍大。
  • 方案2:平衡数据库压力与数据新鲜度,轮询间隔可根据业务需求调整(如10秒、1分钟)。
  • 方案3:实时性最好,但需要DBA授予用户CHANGE NOTIFICATION权限,仅适用于Oracle 11g及以上版本,配置成本高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 19:00:06