ThinkPHP在Swoole协程环境下必须修改database.php三项硬配置:'type' => 'mysql'启用协程MySQL客户端,'deploy' => 0关闭读写分离,'params' => [PDO::ATTR_EMULATE_PREPARES => false]禁用预处理模拟;且数据库操作须在协程内执行,连接池需显式调用Db::pool()。

ThinkPHP 在 Swoole 协程环境下不能直接用默认 database.php 配置跑数据库——不是版本不对,而是连接机制与协程调度根本冲突。必须显式关闭同步特性、启用原生协程驱动,并切断单例复用路径。
database.php 必改三项硬配置
光装扩展没用,以下配置不改,协程数据库永远走不通:
- 'type' => 'mysql':强制使用 Swoole 原生协程 MySQL 客户端,禁用 pdo_mysql(PDO 模式下事务接口不兼容协程对象)
- 'deploy' => 0:关闭读写分离,否则 Connection 类会绕过协程驱动,偷偷创建阻塞式连接
- 'params' => [PDO::ATTR_EMULATE_PREPARES => false]:禁用预处理模拟,否则 SQL 被 PHP 同步拼接,失去协程化意义
另外,'hostname'、'username'、'password' 必须明文写死,不能依赖 getenv() 或 $_ENV —— 协程上下文不保证环境变量始终可读。
禁止在初始化阶段执行数据库操作
协程尚未启动时调用 DB 会直接报错:Swoole\Coroutine\MySQL::query(): must be called in the coroutine。
立即学习“PHP免费学习笔记(深入)”;
- 模型
__construct()中不要做查询或初始化 DB 实例 - 全局 service 或 provider 初始化里避免
Db::table()->find()类操作 - 所有数据库调用必须发生在协程内(如
go()、HTTP 请求回调、命令行 handle 方法中)
连接池不生效?检查调用方式是否正确
即使配置了连接池,90% 的请求仍走短连接,因为默认门面没走池逻辑。
- 必须显式用
Db::pool()->table(...)->find(),不能省略::pool() - 事务要改写为
Db::pool()->transaction(function () { ... }) - 模型中若需池化连接,得重写
db()方法返回Db::pool(),或构造时传入:new UserModel(['db' => Db::pool()]) - 读写分离场景下,
Db::connect('slave')不进池,要用Db::pool()->connect('slave')
服务提供者中接管连接工厂
think-swoole 不会自动替换 Db::connect() 行为,必须手动“劫持”连接创建逻辑:
- 在
app/provider.php或自定义服务提供者中绑定:
use think\swoole\pool\ChannelPool;
Container::getInstance()->bind('db', function ($app) {
$config = $app->config->pull('database');
return new DatabasePool($config, new ChannelPool(64));
});
DatabasePool 会按 Swoole\Coroutine::getuid() 分配隔离连接,确保每个协程独占连接,避免事务、fetch 模式等状态污染。



















