本文目录导读:

- 方案一:使用持久连接(内置机制)
- 方案二:使用Swoole等协程框架(推荐)
- 方案三:中间件代理方案(如ProxySQL、PHP-Middleware)
- 方案四:PHP重连模式(变通方案)
- 如何选择?
- 最佳实践建议
在PHP项目中搭建数据库连接池,通常有以下几种主流方案,由于PHP本身是无共享架构(Share-Nothing)的,每个请求独立执行,因此传统的内存级连接池(如Java的DBCP)在PHP中并不直接适用。
PHP实现连接池主要有以下三种思路:
使用持久连接(内置机制)
这是最简单、最常见的方式,也是PHP原生支持的,它利用了PHP-FPM的进程池特性,每个Worker进程都会缓存一个MySQL连接。
原理:
- 每个PHP-FPM Worker进程在处理完请求后,不会立即关闭与MySQL的连接。
- 下一个请求如果分配到同一个Worker,可直接复用该连接。
代码示例:
<?php
// 使用mysqli的p:前缀,或PDO的持久连接选项
$mysqli = new mysqli('p:localhost', 'user', 'password', 'database');
// 或者PDO
$pdo = new PDO('mysql:host=localhost;dbname=database', 'user', 'password', [
PDO::ATTR_PERSISTENT => true
]);
优缺点:
- ✅ 简单,零依赖
- ✅ 能有效减少连接建立开销
- ❌ 连接数固定为PHP-FPM进程数(通常100-500个)
- ❌ 长时间运行可能导致连接断开(需要配置
wait_timeout和ping重连) - ❌ 不适合跨进程共享连接(每个Worker独立)
适用场景:中小型项目,并发不高的Web应用。
使用Swoole等协程框架(推荐)
Swoole是PHP的协程扩展,支持常驻内存运行,它内置了ConnectionPool连接池管理器,可以在一个进程中创建多个MySQL连接,由所有协程共享。
原理:
- 一个Swoole Worker进程内维护一个连接池(如10-20个连接)。
- 多个协程并发请求时,从池中按需获取/归还连接。
- 实现了真正的连接复用,且支持高并发。
安装:
pecl install swoole
代码示例:
<?php
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
use Swoole\Database\MysqliPool;
use Swoole\Database\MysqliConfig;
// 创建连接池
$pool = new MysqliPool(new MysqliConfig([
'host' => '127.0.0.1',
'port' => 3306,
'user' => 'root',
'password' => 'password',
'database' => 'test',
'strict_type' => true,
]), 10); // 池大小10
// 使用
Coroutine\run(function () use ($pool) {
$conn = $pool->get();
$stmt = $conn->query("SELECT 1");
var_dump($stmt->fetchAll());
$pool->put($conn); // 归还连接
});
优缺点:
- ✅ 真正的连接池,可配置大小、超时、心跳
- ✅ 支持高并发,性能优异
- ✅ 内置故障恢复
- ❌ 需要维护Swoole的进程模型
- ❌ 生态与主流框架不完全兼容(需要适配)
适用场景:高性能API、长连接微服务、WebSocket服务。
中间件代理方案(如ProxySQL、PHP-Middleware)
引入一个专门的数据库中间件(如ProxySQL)来管理连接池,PHP应用只需连接到这个中间件。
原理:
- 在PHP和MySQL之间部署一个代理层。
- 代理负责维护连接池、负载均衡、故障切换。
- PHP使用标准的MySQL客户端连接代理。
架构示意:
PHP App ----> ProxySQL (连接池管理) ----> MySQL Master/Slave
配置示例(ProxySQL):
-- 在ProxySQL管理界面设置连接池大小 set mysql-connection_pool_size=100; set mysql-connection_max_age_seconds=600; save mysql variables;
优缺点:
- ✅ 对PHP代码完全透明,无需修改代码
- ✅ 功能强大(读写分离、健康检查、查询缓存)
- ✅ 支持所有编程语言
- ❌ 增加运维复杂度,需要额外部署和维护
适用场景:大型分布式系统、RDS/云数据库环境。
PHP重连模式(变通方案)
不使用真正的池,而是在PHP代码中模拟池行为,通过全局变量或静态变量在单请求内复用连接。
代码示例:
<?php
class DB {
private static $connections = [];
public static function getConnection($database = 'default') {
if (!isset(self::$connections[$database])) {
self::$connections[$database] = new PDO('mysql:host=...', 'user', 'pass');
}
return self::$connections[$database];
}
}
// 在一次请求中多次调用,只创建一次连接
$conn = DB::getConnection();
优缺点:
- ✅ 简单实用
- ❌ 跨请求无效(每个请求都是新进程)
适用场景:传统MVC框架、每个请求需要多次查询的情况。
如何选择?
| 场景 | 推荐方案 |
|---|---|
| 普通Web项目,PHP-FPM | 方案一(持久连接) |
| 高并发API,长连接服务 | 方案二(Swoole连接池) |
| 已有中间件基础设施 | 方案三(ProxySQL) |
| 单请求内复用连接 | 方案四(静态变量) |
最佳实践建议
- 无论使用哪种方案,请务必配置MySQL的
wait_timeout(建议30s内)和max_connections(根据连接池大小调整)。 - 定期清理超时连接:在Swoole中使用
heartbeat_check_interval;在持久连接中手动检查$conn->ping()。 - 监控连接池状态:统计获取/归还次数、等待队列长度。
- 避免事务中获取连接:确保事务完成后再归还连接到池。
如果是在传统Laravel/Symfony等框架下,建议优先考虑方案一(持久连接);如果想上高性能架构,直接上Swoole连接池是较优选择。