thinkphp 6 默认不支持原生长连接,因其连接池机制会主动销毁 pdo 连接;真正有效的是启用 deploy=1 开启内置连接池复用,并配合 pool_size、pool_time 及 mysql max_connections 调优。

ThinkPHP 6 的 mysql 驱动不支持原生长连接
直接说结论:ThinkPHP 6 默认使用的 PDO 连接方式,即使你在数据库配置里加了 PDO::ATTR_PERSISTENT => true,也大概率无效——因为 TP6 的连接池机制会主动关闭连接,且 mysql(注意不是 mysqlnd)PDO DSN 不识别 persistent 参数。
常见错误现象是:加了持久化配置后,show processlist 里仍看不到复用的连接,QPS 上去后 Too many connections 报错照旧。
- 真正起作用的是底层 MySQL 服务端的
wait_timeout和interactive_timeout,但这是被动等待,不是应用层可控的“长连接复用” - TP6 的
Connection类在__destruct中强制调用$this->pdo = null,PDO 对象销毁即断开,持久化标志被绕过 - 如果你用的是
mysqlnd(现代 PHP 默认),可尝试启用mysqli驱动并配'persistent' => true,但 TP6 官方并不维护 mysqli 连接器
database.php 里写 'persistent' => true 没用,但可以改 'deploy' => 1
TP6 实际提供了一种更务实的替代方案:连接池 + 连接复用,它不依赖 PDO 持久化,而是靠框架自己缓存已建立的 PDO 实例。关键开关是部署模式 deploy。
在 config/database.php 中,把数据库配置块改成:
'mysql' => [
'type' => 'mysql',
'hostname' => '127.0.0.1',
'database' => 'test',
'username' => 'root',
'password' => '',
'hostport' => '3306',
'charset' => 'utf8mb4',
'deploy' => 1, // ← 必须设为 1
'rw_separate' => false,
'master_num' => 1,
'slave_no' => '',
'debug' => false,
],
-
deploy => 1启用读写分离基础结构,即使你没配从库,它也会启用连接复用逻辑 - 配合
'pool_size' => 20(可选)能限制最大空闲连接数,避免 MySQL 端耗尽 - 注意:该机制只对同配置、同数据库名的请求生效;换库名或改账号会导致新建连接池
高并发下真正有效的其实是连接池 + 调整 MySQL max_connections
与其纠结“长连接”,不如盯住两个真实瓶颈点:应用层连接复用效率、服务端连接上限。TP6 的连接池默认不自动清理空闲连接,容易堆积。
建议组合操作:
- MySQL 侧:把
max_connections从默认 151 提到 500+(根据服务器内存调整,每连接约占用 2–3MB) - TP6 侧:在
database.php加上'pool_time' => 3600(单位秒),让空闲连接 1 小时后自动释放 - 加监控:用
SHOW STATUS LIKE 'Threads_connected'查实时连接数,对比Aborted_connects判断是否频繁重连 - 别碰
wait_timeout设太小(如 60),否则连接池里的连接还没复用就断了,反而增加握手开销
用 Db::connect() 手动接管连接时,persistent 才可能生效
如果你在某些高频接口中手动调用 Db::connect() 并传入自定义 DSN,这时 PDO 的持久化才有机会起效——前提是 DSN 显式带上 ;charset=utf8mb4 且不带 new_link 类参数干扰。
示例(仅限特殊场景):
$dsn = 'mysql:host=127.0.0.1;dbname=test;charset=utf8mb4';
$options = [
\PDO::ATTR_PERSISTENT => true,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
];
$conn = new \PDO($dsn, 'root', '', $options);
- 这种写法绕过了 TP6 连接池,适合定时任务或 CLI 场景,但 Web 请求中不推荐——你得自己管理生命周期,否则容易泄露
- PHP-FPM 下,每个 worker 进程会持有一个持久连接,所以连接数 = worker 数 × 数据库实例数,务必算清楚
- 一旦用了这个方式,就别再混用
Db::table(),否则 TP6 可能悄悄新建一个非持久连接
真正在高负载跑稳的关键,从来不是某一个配置开关,而是连接复用逻辑是否和你的部署模型(FPM 进程数、MySQL 连接上限、查询响应时间)对齐。漏掉任意一环,persistent 都只是个幻觉。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










