最简路径是用Docker运行MySQL容器并配置Hyperf连接池:执行docker run -d --name mysql-test -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 mysql:8.0,将db.php中host设为'127.0.0.1'、max_connections调至5、wait_timeout设为5.0,避免本地启停残留连接导致超时卡顿。

Hyperf 本地测试连 MySQL,最简路径是什么
直接用 docker run 起一个 MySQL 容器,配好 config/autoload/db.php 就能跑通基础查询,不用装本地 MySQL、不用改 hosts、不用开防火墙。关键在于容器端口映射和连接池参数调低——否则默认 max_connections=10 在本地反复启停容易残留连接,导致下一次启动卡在 wait_timeout。
- 执行:
docker run -d --name mysql-test -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -v $(pwd)/mysql-data:/var/lib/mysql mysql:8.0 - 确认容器运行:
docker ps | grep mysql-test,看到 STATUS 是 Up 才继续 - 修改
config/autoload/db.php中的host为'127.0.0.1'(不是localhost,Windows/macOS 下localhost会走 socket,而 Docker 映射的是 TCP) - 把
pool.max_connections改成5,pool.wait_timeout提到5.0,避免本地调试时因连接池排队卡住
DB::select() 执行报错 “Connection timeout” 怎么快速定位
不是数据库没起来,也不是密码错了,八成是 connect_timeout 太短 + 网络延迟波动。Hyperf 默认设 10.0 秒,但在 WSL2 或 Docker Desktop 环境下,首次连接可能因 DNS 解析或 NAT 延迟凑满这个阈值。
- 临时加日志:在
app/Command/TestDbCommand.php里用DB::connection()->getPdo()尝试获取原生 PDO 实例,失败时捕获PDOException,看具体 message 是Connection refused还是SQLSTATE[HY000] [2002] - 立刻验证网络:在项目目录执行
telnet 127.0.0.1 3306,通则说明端口可达;不通就检查 Docker 容器是否真在监听 3306(docker exec -it mysql-test netstat -tlnp | grep :3306) - 改配置:把
pool.connect_timeout改成15.0,同时确认options.ATTR_TIMEOUT设为3(这是 query 超时,和连接超时无关,但常被混淆)
为什么 DB::transaction() 在本地测试总回滚失败
事务没生效,不是语法错,而是协程上下文没对齐——Hyperf 的事务绑定在当前协程获取的连接上,如果你在 go() 或 co() 里手动起协程又没显式传连接,就会拿到另一个连接实例,commit 时根本找不到对应事务状态。
- 绝对不要这样写:
go(function () { DB::transaction(...); });—— 新协程里拿的是新连接,跟外层事务无关 - 正确做法:事务块必须在同一个协程内完成,哪怕要并发查其他服务,也用
parallel()包裹,而不是裸写go() - 验证方式:在事务内加
var_dump(DB::connection()->getPdo()->inTransaction());,返回true才算真正进了事务
本地测试完想清空连接池,不重启服务怎么操作
hyperf:pool-status 只能看,不能清。真正有效的清理动作是手动触发连接回收,靠的是 max_idle_time 参数配合主动释放,而不是等它自动超时。
- 临时调低
pool.max_idle_time到5.0(单位秒),然后等 5 秒后所有空闲连接自动关闭 - 更直接的办法:在命令行执行
php bin/hyperf.php hyperf:pool-status查出used数,如果 >0,说明还有业务在用连接,此时硬清会导致正在执行的查询中断;只有used === 0 && wait === 0时才安全 - 开发期建议加个调试命令:
php bin/hyperf.php db:clear-pool(需自己实现,核心是调DB::connection()->getPool()->destroyAll())
本地测试最容易忽略的点:WSL2 下 Docker 容器 IP 不是 127.0.0.1,但端口映射后仍要用 127.0.0.1 访问;Mac 上 Docker Desktop 默认支持 localhost 映射,但某些旧版本需要勾选 “Use the Docker daemon from WSL2” 才生效。这些细节不验证,光改代码没用。



















