thinkphp原生不支持数据库连接池,tp6/8中database.php的pool配置无效;多库高并发需依赖swoole协程池,在config/swoole.php中统一配置并手动初始化多个pdopool实例,同时对齐mysql参数与worker数量。

ThinkPHP 本身不提供数据库连接池,所谓“多数据库连接池”是伪命题——你不能给每个 connections 都配一个独立池,TP 的配置层也不支持。真要实现多库高并发,得靠外部协程池 + 手动路由,而不是改 database.php 里的 pool 字段。
TP6/8 中 database.php 里加 pool 配置完全无效
很多人在 config/database.php 的某个连接里写 'pool' => ['max_connections' => 20],压测时发现连接数照涨不误。这是因为:
- TP6 和 TP8 原生不实现连接池,
pool不是框架识别的合法配置项,会被直接忽略 - 只有启用
think-swoole(且 TP ≥ 8.0.12)后,连接池能力才由 Swoole 层接管,配置入口是config/swoole.php的database节点 - FPM 模式下所有
Db::connect()调用都新建 PDO 实例,'persistent' => true也无效,必须显式传'params' => [PDO::ATTR_PERSISTENT => true],但依然不解决 Sleep 连接堆积
Swoole 协程下多库连接池的唯一可行路径
想让主库、从库、日志库都走池化连接,必须放弃“每个连接配一个池”的幻想,统一交给 Swoole\Database\PDOPool 管理,并按需分发:
- 在
config/swoole.php中只定义一个全局database池配置,enable => true必须开启 - 启动时手动初始化多个
PDOPool实例(例如$masterPool、$slavePool),各自传入不同 DSN - 封装一个
DbPool::connect('mysql_master')工厂方法,内部根据键名返回对应池的get()连接 - 禁止在协程中直接调用
Db::connect('mysql_slave'),它仍会绕过池走原生 PDO
示例关键片段:
$masterPool = new \Swoole\Database\PDOPool([
'dsn' => 'mysql:host=polardb-master.xxxx;dbname=main',
'username' => env('DB_MASTER_USER'),
'password' => env('DB_MASTER_PASS'),
], ['min' => 5, 'max' => 30]);
$slavePool = new \Swoole\Database\PDOPool([
'dsn' => 'mysql:host=polardb-slave.xxxx;dbname=log',
'username' => env('DB_SLAVE_USER'),
'password' => env('DB_SLAVE_PASS'),
], ['min' => 3, 'max' => 20]);
多库场景下最容易被忽略的三个硬限制
即使池代码写对了,仍可能卡在 20 QPS 上不动,问题往往不在 PHP 层:
-
max_connections:PolarDB 按量集群默认仅 200,若你为每个库池设 max=50,又启了 4 个 Worker,则理论最大连接数 = 50 × 4 = 200 —— 刚好打满,MySQL 直接拒连 -
wait_timeout:PolarDB 默认 300 秒,而池的idle_timeout若设为 600,空闲连接在 MySQL 侧先断开,下次取用就报MySQL server has gone away -
innodb_lock_wait_timeout:TP6 连 PolarDB 时若未同步调大该值(建议 ≥ 60),长事务锁等待会直接触发超时中断,不是连接问题,但现象像连接失败
真正要稳住多库高并发,得把池实例、MySQL 参数、Worker 数量三者对齐,而不是堆配置。漏掉任意一层,池就形同虚设。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











