H2数据库查询Promise未解析,阻塞请求问题求助
H2数据库连接Promise始终pending问题排查与解决
问题描述
正在Web服务器中实现H2数据库连接(数据库运行在服务器模式,支持TCP/IP多连接),但每次调用查询函数时,返回的Promise始终处于pending状态——使用await后完全无响应,无法获取查询结果。
技术栈
- Node.js 12.11.0(客户指定版本)
- Express.js(仅需开发3个接口)
- 客户服务器已部署的H2数据库(用于认证)
- SQL Server(存储核心业务数据,认证完成后使用)
相关代码
函数调用
userModel.getUsers();
getUsers函数代码
try { const connection = await h2.getInstance().getConnection(); console.log('Connection established'); return connection.query('SELECT * FROM USERS'); } catch (error) { console.error(error); throw error; }
H2连接类(用pg库通过TCP/IP处理连接,也曾尝试jdbc库,结果一致)
class H2Connection { // 私有静态字段存储单例实例 static #instance = null; // 私有构造函数,禁止直接实例化 constructor() { this.connection = new pg.Client(h2Conf); this.connection.connect(); } static getInstance() { // 实例不存在则创建 if (H2Connection.#instance == null) { H2Connection.#instance = new H2Connection(); } // 返回实例 return H2Connection.#instance; } // 获取连接的方法 getConnection() { return this.connection; } }
已尝试方案
- 切换回调与Promise的处理方式
- 调用函数时使用await,但Promise始终无法解析
- 调试排查未捕获错误,仅看到服务器请求卡在等待循环
- 尝试在Promise外部的局部变量中解析返回结果
期望结果
- 调用服务后能正常输出日志(不用await时能输出日志,但变量值为undefined)
- 使用then-catch时能输出日志(目前无任何日志输出)
- 能获取数组或JSON格式的查询结果
问题根源与修复方案
1. 核心问题分析
- 连接建立未异步等待:
H2Connection构造函数中this.connection.connect()是异步操作,但未处理Promise,导致getConnection()返回的连接可能未完成建立,后续query调用卡住。 - pg库适配兼容性:pg库为PostgreSQL设计,虽H2兼容部分PG协议,但仍可能存在Promise解析异常的兼容性问题。
- 单例异步初始化缺陷:单例构造函数同步执行,无法处理异步连接逻辑,实例返回时连接未就绪。
2. 针对性修复
方案一:修复连接类的异步初始化逻辑
修改单例模式,确保连接建立完成后再返回实例:
class H2Connection { static #instance = null; static #connectionPromise = null; // 存储连接初始化Promise,避免重复初始化 constructor() { this.connection = new pg.Client(h2Conf); } static async getInstance() { if (!H2Connection.#instance) { if (!H2Connection.#connectionPromise) { H2Connection.#connectionPromise = (async () => { const instance = new H2Connection(); await instance.connection.connect(); // 等待连接建立完成 H2Connection.#instance = instance; return instance; })(); } await H2Connection.#connectionPromise; } return H2Connection.#instance; } getConnection() { return this.connection; } }
同步修改getUsers函数,等待实例初始化完成:
try { const h2Instance = await h2.getInstance(); // 等待实例初始化 const connection = h2Instance.getConnection(); console.log('Connection established'); const result = await connection.query('SELECT * FROM USERS'); // 等待查询完成 return result.rows; // 返回格式化后的结果 } catch (error) { console.error(error); throw error; }
方案二:更换H2专用驱动(推荐)
pg库并非H2官方适配驱动,建议改用jdbc库并修复异步逻辑:
const jdbc = require('jdbc'); const jinst = require('jdbc/lib/jinst'); // 初始化JVM(仅需执行一次) if (!jinst.isJvmCreated()) { jinst.addOption('-Xrs'); jinst.setupClasspath(['path/to/h2-*.jar']); // 替换为实际H2驱动路径 } class H2Connection { static #instance = null; static #connectionPromise = null; constructor() { this.config = { url: 'jdbc:h2:tcp://<host>:<port>/<dbname>', // 替换为实际H2地址 user: '<username>', password: '<password>', drivername: 'org.h2.Driver', minpoolsize: 1, maxpoolsize: 10 }; this.jdbcConn = new jdbc(this.config); } static async getInstance() { if (!H2Connection.#instance) { if (!H2Connection.#connectionPromise) { H2Connection.#connectionPromise = (async () => { const instance = new H2Connection(); await instance.jdbcConn.initialize(); // 初始化驱动 const conn = await instance.jdbcConn.reserve(); // 获取连接 instance.connection = conn; H2Connection.#instance = instance; return instance; })(); } await H2Connection.#connectionPromise; } return H2Connection.#instance; } async query(sql) { const statement = await this.connection.createStatement(); const resultSet = await statement.executeQuery(sql); const rows = await resultSet.toObjArray(); // 转换为JSON数组 await statement.close(); await this.jdbcConn.release(this.connection); // 释放连接回池 return rows; } }
方案三:Express路由中正确使用await
确保接口调用时正确处理异步逻辑:
app.get('/users', async (req, res) => { try { const users = await userModel.getUsers(); res.json(users); } catch (err) { res.status(500).json({ error: err.message }); } });
3. 验证要点
- 确认H2服务器正常启动,TCP端口开放,防火墙允许连接
- 核对数据库配置(地址、端口、用户名、密码、库名)完全正确
- 查看H2服务器日志,排查连接失败或查询错误记录
内容的提问来源于stack exchange,提问作者Arturo Obregon
相关产品推荐
相关产品推荐

