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

NestJS+TypeORM+MySQL2连接关闭状态下无法新增命令问题求助

解决TypeORM + MySQL运行数小时后出现“Can't add new command when connection is in closed state”错误

问题根源

这个错误本质是MySQL服务器主动断开了闲置过久的连接,而TypeORM的连接池未检测到连接已失效,继续使用该断开的连接执行查询时就会触发报错。MySQL默认的wait_timeout和interactive_timeout为8小时,超过这个时长的闲置连接会被服务器主动关闭。

可行解决方案

1. 配置TypeORM连接池的连接保活与有效性检测

修改data-source.ts,添加连接池相关配置,让连接池主动维持连接有效性:

export default new DataSource({
  name: 'default',
  type: 'mysql',
  host: DatabaseConfig.DB_HOST,
  port: DatabaseConfig.DB_PORT,
  username: DatabaseConfig.DB_USERNAME,
  password: DatabaseConfig.DB_PASSWORD,
  database: DatabaseConfig.DB_NAME,
  synchronize: DatabaseConfig.IS_SYNCHRONIZE,
  logging: DatabaseConfig.DB_LOG_ENABLE ? 'all' : false,
  logger: DatabaseConfig.DB_LOG_ENABLE ? TypeOrmLogger.new() : undefined,
  entities: [`${TypeOrmDirectory}/entity/**/*{.ts,.js}`],
  migrations: [`${TypeOrmDirectory}/migration/**/*{.ts,.js}`],
  migrationsTransactionMode: 'all',
  // 新增连接池配置
  extra: {
    connectionLimit: 10, // 根据业务流量调整连接池大小
    waitForConnections: true,
    queueLimit: 0,
    // 开启连接保活,定期发送心跳包防止被MySQL断开
    enableKeepAlive: true,
    keepAliveInitialDelay: 300000, // 5分钟后开始发送保活包(需小于MySQL的8小时超时)
    // 检测连接有效性
    connectionTimeoutMillis: 2000, // 获取连接超时时间
    acquireTimeoutMillis: 2000,
    validateConnection: true, // 每次从连接池获取连接时验证是否可用
  },
});

2. 实现连接断开后的自动重连机制

在InfraModule中监听数据库连接错误,当检测到连接断开时自动重新初始化连接:

@Global()
@Module({
  imports: [HttpModule],
  providers: [...providers, ...databaseProviders],
  exports: [
    InfraDITokens.DataSource,
    InfraDITokens.EmailSenderService,
    InfraDITokens.FyGatewayService,
  ],
})
export class InfraModule implements OnApplicationBootstrap, OnModuleDestroy {
  private dataSource: DataSource;

  constructor(@Inject(InfraDITokens.DataSource) dataSource: DataSource) {
    this.dataSource = dataSource;
  }

  onApplicationBootstrap(): void {
    // 监听连接错误事件
    this.dataSource.driver.connection.on('error', async (err) => {
      const isConnectionLost = err.message.includes('closed state') || err.code === 'PROTOCOL_CONNECTION_LOST';
      if (isConnectionLost) {
        console.error('数据库连接已断开,启动重连流程...');
        await this.handleReconnect();
      }
    });
  }

  private async handleReconnect(): Promise<void> {
    try {
      // 先销毁旧连接实例
      await this.dataSource.destroy();
      // 重新初始化连接
      await this.dataSource.initialize();
      console.log('数据库连接重连成功');
    } catch (reconnectErr) {
      console.error('重连失败,5秒后重试:', reconnectErr);
      // 可添加重试次数限制避免无限循环
      setTimeout(() => this.handleReconnect(), 5000);
    }
  }

  onModuleDestroy(): void {
    // 应用关闭时销毁连接
    this.dataSource.destroy().catch(err => console.error('销毁数据库连接失败:', err));
  }
}

3. 调整MySQL服务器的超时配置(可选,需服务器权限)

如果有权限修改MySQL配置文件(my.cnf或my.ini),可以延长连接超时时间:

wait_timeout = 288000   # 设置为80小时(根据业务需求调整)
interactive_timeout = 288000

修改后重启MySQL服务即可。不过该方案仅能延缓问题,无法彻底避免连接断开的情况,建议结合前两种方案使用。

验证方案

部署修改后的代码后,持续观察系统运行状态,若不再出现该错误则说明配置生效。若仍有问题,可检查TypeORM日志确认连接保活包是否正常发送,或排查是否存在网络波动等其他导致连接断开的因素。

内容的提问来源于stack exchange,提问作者Guilherme Colares

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 21:05:00