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

Node.js OracleDB报错:connection.execute is not a function 问题求助

问题分析

你遇到的TypeError: connection.execute is not a function错误,核心原因有两个:

  1. lib/db.js中的connection函数没有返回数据库连接实例:await oracledb.getConnection(...)执行后没有return,导致调用该函数得到的Promise最终返回undefined。
  2. 路由代码中直接调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 23:25:19