Node.js OracleDB报错:connection.execute is not a function 问题求助
问题分析
你遇到的TypeError: connection.execute is not a function错误,核心原因有两个:
lib/db.js中的connection函数没有返回数据库连接实例:await oracledb.getConnection(...)执行后没有return,导致调用该函数得到的Promise最终返回undefined。- 路由代码中直接调用
connection.execute:你导入的connection是一个async函数,并非实际的数据库连接对象,自然不存在execute方法。
另外,你提到的“每次执行语句重新建立连接”确实不是最优方案,频繁创建/销毁连接会带来性能损耗,数据库连接池才是更合理的复用方案。
解决方案一:修正基础连接逻辑(非连接池)
先修复当前报错,保证单连接正常工作,再升级到连接池方案。
1. 修正lib/db.js
让函数正确返回数据库连接实例:
const oracledb = require('oracledb'); async function getConnection() { try { const connection = await oracledb.getConnection({ user: "user", password: "password", connectString: "hostname" }); return connection; } catch (err) { console.error('获取数据库连接失败:', err); throw err; } } module.exports = { getConnection };
2. 修正路由代码
使用async/await获取连接,执行SQL后主动释放连接,同时用绑定变量防止SQL注入:
var express = require('express'); var router = express.Router(); var { getConnection } = require('../lib/db'); // 显示编辑用户表单 router.get('/edit/(:id)', async function(req, res, next) { let connection; try { // 获取数据库连接 connection = await getConnection(); // 使用绑定变量执行SQL,避免注入风险 const result = await connection.execute( 'SELECT * FROM customers WHERE id = :id', [req.params.id], { outFormat: oracledb.OBJECT } // 以对象形式返回结果 ); // 处理查询结果 if (result.rows.length <= 0) { req.flash('error', '未找到ID为' + req.params.id + '的客户'); res.redirect('/customers'); } else { const customer = result.rows[0]; res.render('customers/edit', { title: '编辑客户', id: customer.id, name: customer.name, email: customer.email }); } } catch (err) { // 交给Express错误处理中间件处理 next(err); } finally { // 无论成功失败,都释放连接 if (connection) { try { await connection.release(); } catch (err) { console.error('释放连接失败:', err); } } } });
解决方案二:最优方案——使用数据库连接池
连接池会预先创建并维护一批数据库连接,请求时从池里取连接,使用完放回池里,避免频繁创建/销毁连接的开销,大幅提升性能。
1. 重构lib/db.js为连接池模式
const oracledb = require('oracledb'); // 连接池配置可根据业务调整 const poolConfig = { user: "user", password: "password", connectString: "hostname", poolMin: 2, // 最小空闲连接数 poolMax: 10, // 连接池最大连接数 poolIncrement: 1 // 连接不足时每次新增的数量 }; // 初始化连接池 async function initPool() { try { await oracledb.createPool(poolConfig); console.log('数据库连接池初始化成功'); } catch (err) { console.error('初始化连接池失败:', err); throw err; } } // 从连接池获取连接 async function getConnectionFromPool() { try { const connection = await oracledb.getConnection(); return connection; } catch (err) { console.error('从连接池获取连接失败:', err); throw err; } } // 应用关闭时关闭连接池 async function closePool() { try { await oracledb.getPool().close(10); // 10秒超时时间 console.log('连接池已关闭'); } catch (err) { console.error('关闭连接池失败:', err); } } module.exports = { initPool, getConnectionFromPool, closePool };
2. 在app.js中初始化连接池
确保Express启动前先完成连接池初始化:
const express = require('express'); const { initPool, closePool } = require('./lib/db'); const app = express(); // 初始化连接池后启动服务 initPool().then(() => { app.listen(3000, () => { console.log('服务器运行在端口3000'); }); }).catch(err => { console.error('应用启动失败:', err); process.exit(1); }); // 应用终止时关闭连接池 process.on('SIGINT', async () => { await closePool(); process.exit(0); });
3. 路由中使用连接池连接
用法和单连接类似,只是获取连接的函数换成getConnectionFromPool,释放连接后连接会回到池中复用:
var express = require('express'); var router = express.Router(); var { getConnectionFromPool } = require('../lib/db'); // 显示编辑用户表单 router.get('/edit/(:id)', async function(req, res, next) { let connection; try { connection = await getConnectionFromPool(); const result = await connection.execute( 'SELECT * FROM customers WHERE id = :id', [req.params.id], { outFormat: oracledb.OBJECT } ); if (result.rows.length <= 0) { req.flash('error', '未找到ID为' + req.params.id + '的客户'); res.redirect('/customers'); } else { const customer = result.rows[0]; res.render('customers/edit', { title: '编辑客户', id: customer.id, name: customer.name, email: customer.email }); } } catch (err) { next(err); } finally { if (connection) { try { await connection.release(); // 连接放回连接池 } catch (err) { console.error('释放连接失败:', err); } } } });
内容的提问来源于stack exchange,提问作者user2829319
相关产品推荐
相关产品推荐

