如何在TypeScript/JavaScript中编写数据库重连与查询重试逻辑
问题分析与修正实现
你的代码存在几个关键问题:
connect每次重试都会创建新连接实例,未清理旧实例,易引发资源泄漏;递归调用无终止条件,连接成功后可能仍有残留的重试逻辑query重试时未绑定初始Promise的resolve,导致首次失败后后续成功无法正确返回结果;未区分「查询无结果」和「查询错误」,不符合仅返回有记录结果的要求
以下是符合需求的正确实现:
import mysql from 'mysql2/promise'; // 改用mysql2的Promise API,更贴合async/await写法 import dotenv from 'dotenv'; dotenv.config(); const RETRY_INTERVAL = parseInt(process.env.DB_RETRY_INTERVAL || '5000', 10); class Database { private connection: mysql.Connection | null = null; private config: mysql.ConnectionOptions; private isConnecting = false; // 防止并发重复发起连接请求 constructor(config: mysql.ConnectionOptions) { this.config = config; } /** * 持续重试连接,直到成功,不返回控制权、不抛异常 */ public async connect(): Promise<void> { if (this.isConnecting) return; // 避免重复发起连接 this.isConnecting = true; try { this.connection = await mysql.createConnection(this.config); console.log(`数据库连接成功: ${this.config.database}`); // 监听连接断开事件,自动触发重连 this.connection.on('error', (err) => { console.error(`数据库连接断开,开始重试: ${err.message}`); this.connection = null; this.connect(); }); } catch (err: any) { console.error(`连接失败,${RETRY_INTERVAL}ms后重试: ${err.message},主机: ${this.config.host},端口: ${this.config.port}`); setTimeout(() => { this.isConnecting = false; this.connect(); }, RETRY_INTERVAL); } } /** * 持续重试查询,直到查询到有效记录才返回结果,不返回控制权、不抛异常 */ public async query(sql: string): Promise<any[]> { if (!this.connection) { // 若未连接,先等待连接建立(利用事件循环,避免阻塞) await new Promise(resolve => setTimeout(resolve, 100)); return this.query(sql); } try { const [rows] = await this.connection.execute(sql); const resultRows = rows as any[]; if (resultRows.length === 0) { console.log(`查询无结果,${RETRY_INTERVAL}ms后重试: ${sql}`); await new Promise(resolve => setTimeout(resolve, RETRY_INTERVAL)); return this.query(sql); } return resultRows; } catch (err: any) { console.error(`查询失败,${RETRY_INTERVAL}ms后重试: ${err.message},SQL: ${sql}`); await new Promise(resolve => setTimeout(resolve, RETRY_INTERVAL)); return this.query(sql); } } } export default Database;
关键改进点
- 改用
mysql2/promise的Promise化API,避免回调嵌套,更易维护 - 新增
isConnecting标记,防止并发重复发起连接请求 - 连接成功后监听
error事件,断开时自动触发重连 query函数确保只有查询到非空结果才返回,无结果时继续重试- 重试逻辑使用async/await替代setTimeout递归,避免回调地狱,同时保证初始Promise能正确接收最终结果
- 统一处理未连接状态,查询前自动等待连接建立
内容的提问来源于stack exchange,提问作者Syed Rafey Husain
相关产品推荐
相关产品推荐

