Hyperf中Db连接不随协程结束自动释放,其生命周期由连接池管理;实际释放分三种情况:正常归还(方法返回时)、超时回收(空闲超max_idle_time)、显式关闭(调用close())。

Hyperf 中的数据库连接(Db)在协程环境下不是自动释放的,它的生命周期由连接池管理,协程结束 ≠ 连接释放。真正决定连接何时归还给连接池的关键,是「是否显式关闭」或「是否超出空闲等待时间」。
协程结束时,Db连接不会自动释放
- Hyperf 使用 Swoole 连接池(如
Hyperf\Database\Pool\Pool),每个协程从池中获取的是一个复用的 PDO 或 MySQLi 实例,不是全新创建的连接; - 协程执行完、上下文销毁,只代表该协程不再持有这个连接对象,但连接本身仍留在池中等待复用;
- 若未调用
close()或未触发超时回收,连接会一直保留在池中,直到被其他协程取走,或被连接池的空闲回收机制清理。
连接实际释放的三种情况
-
正常归还:协程内完成查询后,连接会在方法返回时自动归还给连接池(前提是没手动
close(),也没发生异常中断); -
超时回收:连接在池中空闲超过
max_idle_time(默认 60 秒),连接池定时器会主动 close 并销毁该连接; -
显式关闭:调用
$db->close()或使用DB::connection()->getPdo()->close(),会立即释放底层 socket 并从池中移除该连接实例。
容易踩坑的典型场景
- 在长生命周期协程(如异步任务、定时任务)中反复执行 DB 操作却不释放连接,可能导致连接池耗尽;
- 使用
DB::transaction()后未提交或回滚,事务锁和连接会持续占用,协程结束也不释放; - 在
try/catch中捕获异常但忘记rollback(),连接卡在事务中,后续协程可能因拿不到可用连接而阻塞。
推荐做法
- 依赖框架默认行为即可,不用手动
close(),除非你明确需要立即释放; - 长事务务必设置
DB::transaction(fn () => ..., $timeout)超时参数; - 监控连接池水位:通过
swoole_server->stats()查看db_pool_used_connections等指标; - 开发期可临时开启
pool.max_connections = 2+ 高并发压测,快速暴露连接泄漏问题。
不复杂但容易忽略。











