如何循环执行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
相关产品推荐
相关产品推荐

