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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 02:10:36