Laravel默认无数据库连接池,因PHP-FPM无状态特性无法跨请求复用连接;仅在Swoole等常驻进程环境中可通过协程实现真正连接池。
为什么 Laravel 默认没有数据库连接池
Laravel 底层用的是 PDO,而 PDO 本身不维护连接池——每次
或模型查询,都可能新建或复用一个 PHP-FPM 进程内的 PDO 实例,但这个“复用”仅限于当前请求生命周期。PHP 的无状态特性决定了它无法跨请求共享数据库连接,所以严格来说,Laravel 没有、也不可能原生实现传统意义上的连接池(如 Go 的
或 Java 的 HikariCP)。
常见错误现象:
,尤其在压测或队列集中消费时爆发,不是因为 Laravel “没配好”,而是 MySQL 的
被瞬时打满,根源在于短连接高频创建 + FPM 子进程数配置过高 + 查询未及时释放。
不要试图用
或手动
来“模拟池化”——它解决不了连接数上限问题
连接复用只发生在单次请求内,
和后续同连接的
共享同一个 PDO 实例,但下个请求必然重连
如果你用的是 Swoole 或 RoadRunner 这类常驻内存服务器,才真正具备实现连接池的基础;否则所有“Laravel 连接池扩展”本质只是连接缓存或连接代理,不改变 MySQL 侧连接计数逻辑
高并发下真正有效的三板斧
与其纠结“怎么加连接池”,不如直面 Laravel 在 FPM 场景下的实际瓶颈:连接创建开销、空闲连接堆积、慢查询拖垮整体。
调低 MySQL 的
(建议 60–120 秒),避免 PHP 进程崩溃后连接在 MySQL 侧长期滞留
在
的 MySQL 配置里加上
,防止个别查询卡死导致连接被占住
强制使用连接读写分离时,确保
和
都配置了
为
,否则事务中后续读可能落到从库,引发数据不一致
队列任务里避免在循环中反复调用
—— 改用
批量查,减少连接往返次数
Swoole 场景下可用的连接池方案(仅限常驻进程)
只有当你已切换到 Swoole HTTP Server 或使用
时,“连接池”才有落地意义。此时每个 Worker 进程可持有一组长连接,由协程调度复用。
Laravel 13.2.0
PHP中文网提供Laravel 13.2.0版本下载,Laravel框架 是基于 PHP 8.3+ 的高性能框架,官方推荐通过 Composer 安装。它内置 AI SDK、JSON:API Resources 及原生向量搜索,支持属性驱动开发与队列路由,大幅提升开发效率。相比旧版,13.2.0 优化了缓存 TTL 管理与实时通信,无需 Redis 即可横向扩展。作为现代 Web 开发首选,它兼顾安全与极速体验,助您快速构建企业级应用。
下载
示例关键配置(
):
必须配合
v3+ 或自研协程适配层,原生 Laravel 不识别
配置项
不宜设过高——每个 Worker 独立维护一份池,总连接数 = Worker 数 × max_connections,仍可能冲垮 MySQL
务必关闭
日志监听,协程环境下它会导致上下文错乱和内存泄漏
最容易被忽略的性能断点:DNS 解析与 SSL 握手
在云环境(尤其是跨 AZ 或容器部署)中,
写域名而非 IP,且未开启 DNS 缓存,会导致每次连接都触发同步 DNS 查询;若启用了 MySQL SSL,完整握手耗时可能达 200ms+,远超查询本身。
把
改成内网 IP(如
),跳过 DNS 查找
确认 MySQL 是否真需要 SSL:如果应用和 DB 同 VPC/集群内,关掉
选项,性能提升明显
检查
是否被防火墙/NAT 设备干扰——某些云厂商的 SLB 对短连接重试策略激进,会放大连接失败率
用
抓包验证真实连接耗时分布,别只信 Laravel 日志里的 query time
事情说清了就结束。
DB::connection()database/sqlSQLSTATE[HY000] [1040] Too many connectionsmax_connectionsDB::reconnect()DB::disconnect()DB::table('users')->first()->where(...)->get()wait_timeoutconfig/database.php'options' => [PDO::ATTR_TIMEOUT => 5]readwritestickytrueModel::find()Model::whereIn('id', $ids)->get()->keyBy('id')swooletw/laravel-swooleconfig/database.php'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
// 注意:这里不能写 localhost,Swoole 下会走 socket 导致连接失败
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
PDO::MYSQL_ATTR_SSL_CERT => env('MYSQL_ATTR_SSL_CERT'),
PDO::MYSQL_ATTR_SSL_KEY => env('MYSQL_ATTR_SSL_KEY'),
]) : [],
// 关键:启用 Swoole 协程 MySQL 连接池(需安装 ext-swoole)
'pool' => [
'min_connections' => 1,
'max_connections' => 32,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
],
],
swooletw/laravel-swoolepoolmax_connectionsDB::listen()DB_HOSTDB_HOST10.10.1.23MYSQL_ATTR_SSL_*DB_PORTtcpdump