0

0

TypeScript/JavaScript 中实现健壮的数据库连接重试逻辑

聖光之護

聖光之護

发布时间:2026-02-12 18:03:12

|

922人浏览过

|

来源于php中文网

原创

TypeScript/JavaScript 中实现健壮的数据库连接重试逻辑

本文介绍如何在 node.js 环境中使用 typescriptjavascript 编写具备自动重试能力的 mysql 数据库连接与查询逻辑,支持可配置最大重试次数与间隔,并确保连接失败时不崩溃、不提前返回,符合生产级容错要求。

在构建高可用后端服务时,数据库临时不可用(如维护重启、网络抖动、容器启动延迟)是常见场景。若连接逻辑缺乏重试机制,应用可能快速失败甚至退出。原问题中提供的递归 setTimeout + 异步回调方案存在明显缺陷:无法控制重试上限、无法统一错误处理、易导致调用栈爆炸或内存泄漏,且 query 方法未集成重试逻辑,违背“失败即重试”的设计目标

以下是一个专业、可维护、生产就绪的重试实现方案,核心改进包括:

PpcyAI
PpcyAI

泡泡次元AI-游戏美术AI创作平台,低门槛上手,高度可控,让你的创意秒速落地

下载
  • 分离关注点:将通用重试逻辑抽象为独立的 retry 工具方法,支持任意 Promise 返回函数;
  • 可控重试策略:支持最大重试次数(maxRetries)和固定延迟(delay),负值表示无限重试;
  • 连接阶段强保障:connect() 方法内部封装连接过程为 Promise,并通过 retry() 保证最终成功或明确超限失败;
  • 查询阶段按需重试:query() 本身不内置重试(避免无界重试掩盖 SQL 错误),但可轻松组合 retry() 实现语义化重试(见后文示例);
  • 类型安全与可读性:使用现代 async/await + Promise 风格,规避回调地狱,便于 TypeScript 类型推导。

✅ 推荐实现(TypeScript 兼容)

import mysql from 'mysql';

interface DbConfig {
  host: string;
  user: string;
  password: string;
  port: string | number;
  database?: string;
}

class Database {
  connection: mysql.Connection | null = null;
  config?: DbConfig;

  // 通用重试工具:适用于任意返回 Promise 的操作
  retry<T>(
    fn: () => Promise<T>,
    maxRetries: number,
    delay: number
  ): Promise<T> {
    return new Promise((resolve, reject) => {
      let attempts = 0;

      const attempt = () => {
        fn()
          .then(result => resolve(result))
          .catch(error => {
            attempts++;
            if (maxRetries < 0 || attempts <= maxRetries) {
              console.warn(
                `[DB Retry] Attempt ${attempts}/${maxRetries === -1 ? '∞' : maxRetries} failed:`,
                error instanceof Error ? error.message : String(error)
              );
              setTimeout(attempt, delay);
            } else {
              reject(
                new Error(
                  `Max retries (${maxRetries}) exceeded. Last error: ${
                    error instanceof Error ? error.message : String(error)
                  }`
                )
              );
            }
          });
      };

      attempt();
    });
  }

  // 建立带重试的数据库连接
  async connect(config: DbConfig): Promise<void> {
    const connectOnce = (): Promise<mysql.Connection> => {
      return new Promise((resolve, reject) => {
        const conn = mysql.createConnection(config);
        conn.connect(err => {
          if (err) reject(err);
          else resolve(conn);
        });
      });
    };

    try {
      const conn = await this.retry(
        connectOnce,
        parseInt(process.env.DB_MAX_RETRY || '5', 10),
        parseInt(process.env.DB_RETRY_INTERVAL || '5000', 10)
      );
      this.connection = conn;
      this.config = config;
      console.log(`✅ Database connected: ${config.database || '(no DB name)'}`);
    } catch (err) {
      console.error('❌ Failed to establish database connection after retries:', err);
      throw err; // 让调用方决定是否兜底(如降级、告警)
    }
  }

  // 基础查询方法(无重试)——保持职责单一
  async query(sql: string, values?: any[]): Promise<any[]> {
    if (!this.connection) {
      throw new Error('Database not connected. Call connect() first.');
    }

    return new Promise((resolve, reject) => {
      this.connection!.query(sql, values, (err, results) => {
        if (err) reject(err);
        else resolve(results);
      });
    });
  }

  // 可选:封装带重试的查询(适用于幂等读操作)
  async queryWithRetry(
    sql: string,
    values?: any[],
    maxRetries = 3,
    delay = 2000
  ): Promise<any[]> {
    return this.retry(
      () => this.query(sql, values),
      maxRetries,
      delay
    );
  }

  // 安全关闭连接
  close(): void {
    if (this.connection) {
      this.connection.end();
      this.connection = null;
      console.log('? Database connection closed.');
    }
  }
}

export default Database;

? 使用示例

import Database from './Database';

const db = new Database();

// 启动时自动重连(阻塞式初始化)
async function initDatabase() {
  const config = {
    host: process.env.DB_HOST || 'localhost',
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    port: process.env.DB_PORT || 3306,
    database: process.env.DB_NAME,
  };

  console.log('⏳ Initializing database connection...');
  try {
    await db.connect(config);
    console.log('? Database ready.');

    // 示例:带重试的健康检查查询
    const result = await db.queryWithRetry('SELECT 1 AS alive', 3, 1000);
    console.log('Health check:', result);

  } catch (error) {
    console.error('? Critical: DB initialization failed.', error);
    process.exit(1); // 或触发熔断/告警
  }
}

initDatabase();

⚠️ 关键注意事项

  • 环境变量校验:务必在启动前校验 DB_MAX_RETRY 和 DB_RETRY_INTERVAL,避免 NaN 导致无限重试;
  • 连接泄漏防护:每次 createConnection 失败后,旧连接若已部分建立需手动 .end() 或 .destroy()(本例中因连接未成功,无需显式销毁);
  • 幂等性原则:仅对 SELECT 等安全操作启用查询重试;INSERT/UPDATE 等非幂等操作重试可能导致数据异常,应结合事务与唯一约束保障;
  • 监控与告警:在 retry 的 console.warn 中加入指标上报(如 Prometheus Counter),便于观测重试频次;
  • 替代方案建议:生产环境推荐使用 mysql2(支持 Promise API 和连接池)+ generic-pool,进一步提升稳定性和性能。

通过以上设计,你将获得一个清晰、可测试、可扩展且符合 Node.js 最佳实践的数据库重试方案,既解决启动期连接韧性问题,也为运行时查询容错提供灵活基础。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

901

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

333

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

372

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1572

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

368

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

1148

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

583

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

433

2024.04.29

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

4

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 5万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.9万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号