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
相关产品推荐
相关产品推荐

