ThinkPHP 8.0 真正启用 Swoole 协程 MySQL 连接池需运行于 think-swoole 启动的协程服务器,禁用 Db::connect(),改用 SwooleCoroutineMySQL 或 thinkswoolepoolDatabasePool 手动集成,并配置心跳与合理池大小。

ThinkPHP 8.0 要真正用上 Swoole 协程 MySQL 连接池,关键不是改 database.php 里的某个开关,而是切换执行环境和连接方式——必须运行在 think-swoole 启动的协程服务器上,并绕过 Db::connect() 的默认 PDO 行为,改用 Swoole 原生协程客户端 + 池化管理。
确认运行环境与版本前提
TP 8.0 本身不带连接池,只有在 Swoole 协程上下文中才可能复用连接。需同时满足:
- PHP 环境已安装 Swoole 扩展(≥ 4.8.0),且启用协程支持
- 项目已安装 topthink/think-swoole(建议 ≥ 4.0.12),并用
php think swoole启动服务 - ThinkPHP 版本 ≥ 8.0.12(早期 8.0.x 存在协程适配 bug)
- database.php 中数据库配置完整:
'type' => 'mysql'、'hostname'、'username'、'password'、'database'缺一不可
禁用 Db::connect(),改用 SwooleCoroutineMySQL
Db::connect() 在协程内仍会创建新 PDO 实例,无法池化。正确做法是:完全不走 TP 的 Db 门面,直接使用 Swoole 协程 MySQL 客户端。
- 在业务逻辑中用
go(function () { $mysql = new SwooleCoroutineMySQL(); $mysql->connect($config); ... }); - 或封装成连接池类,通过
$pool->get()获取连接,执行完必须$pool->put($mysql)归还,不能调close() - 避免在构造函数、同步中间件、定时任务回调里提前调用数据库操作——协程一旦切出,连接就丢失
手动集成 think-swoole 的 DatabasePool(推荐)
think-swoole 自带 thinkswoolepoolDatabasePool,但它不会自动接管 Db::connect(),需要显式绑定:
立即学习“PHP免费学习笔记(深入)”;
- 在
app/provider.php或自定义服务提供者中添加:
Container::getInstance()->bind('db', function ($app) {
$config = $app->config->pull('database');
return new hinkswoolepoolDatabasePool($config, new hinkswoolepoolChannelPool(64));
});
- 池大小建议设为
max_request × 2(如 Swoole 配置max_request => 3000,池大小设 60–100);太大易 OOM,太小导致频繁新建销毁 - DatabasePool 会按
SwooleCoroutine::getuid()分配连接,确保同协程内复用
事务与心跳必须单独处理
事务和空闲断连是两个高频踩坑点:
- 事务必须包裹在同一协程内:
go(function () { Db::transaction(function () { ... }); });,否则连接无法归池 - MySQL 默认
wait_timeout = 8秒,闲置连接会被 kill。需在 Swoole 配置中开启心跳:'options' => ['timeout' => 5, 'heartbeat' => 3](每 3 秒 ping 一次) - 数据库侧同步执行:
SET GLOBAL wait_timeout = 300;(需 SUPER 权限) - database.php 中不要设
'break_reconnect' => true,它会干扰协程下的自动重连逻辑



















