Db协程是底层协程化数据库执行引擎,模型协程是依赖Db协程能力的Eloquent封装层;前者基于Swoole协程驱动实现非阻塞I/O与连接池管理,后者通过复用Db协程能力实现协程安全操作,但自身不自动协程化。

Hyperf 中的 Db 协程 和 模型协程 不是两种独立的“协程类型”,而是指在使用 Hyperf 数据访问层时,底层驱动是否真正协程化、调用方式是否适配协程上下文的两个不同层次的表现。它们的区别核心在于:Db 是底层协程化数据库操作的执行引擎,模型(Eloquent)是构建在其之上的、封装了业务逻辑的协程友好层——但模型本身不自动协程化,它依赖 Db 的协程能力才能真正异步。
Db 协程:Swoole 驱动的协程化数据库连接池
这是 Hyperf 实现高并发数据库访问的基石。
- Db 组件基于 Swoole 协程 MySQL/PostgreSQL 客户端(如
Swoole\Coroutine\MySQL),所有 SQL 执行(query、execute、beginTransaction等)默认是非阻塞的。 - 它内置连接池管理,每个 Worker 进程维护独立的协程安全连接池,避免连接复用冲突。
- 直接使用
Hyperf\Database\Connection或DB::select()时,操作天然运行在当前协程中,I/O 等待时自动让出 CPU,不阻塞其他请求。 - ✅ 关键特征:
- 使用原生 PDO 封装 + Swoole 协程驱动
- 支持超时控制(
setWaitTimeout)、连接健康检查、自动重连 - 可手动切换连接、事务嵌套、读写分离
示例:
use Hyperf\DbConnection\Db;
$result = Db::table('users')->where('id', 1)->first(); // 协程安全,无阻塞模型协程:Eloquent 模型 + Db 协程能力的组合体
Eloquent 模型本身是同步设计的 ORM,但在 Hyperf 中通过以下方式获得协程能力:
- 模型底层完全依赖
Hyperf\Database\Connection(即上面的 Db 协程),所以User::find(1)、$user->save()等操作,最终都走的是协程化的 Db 执行链。 - 但要注意:模型方法不是“自动协程函数”。比如你在协程里调用
$model->load('profile'),它会触发协程化的关联查询;但如果你在模型里写了sleep(1)或file_get_contents(),就会直接卡死整个 Worker。 - 模型的生命周期绑定协程上下文(例如
RequestContext、DatabaseTransaction),事务状态、连接选择、日志上下文等都按协程隔离,不会跨协程污染。
✅ 正确用法:
co(function () {
$user = User::where('id', 1)->first(); // ✅ 协程安全
$user->name = 'new';
$user->save(); // ✅ 底层走 Db 协程连接
});❌ 错误用法:
co(function () {
$user = User::find(1);
sleep(1); // ❌ 同步阻塞,挂起整个 Worker
$user->refresh(); // 这行可能永远等不到
});常见误区澄清
- “模型自带协程”是错觉:Eloquent 没有自己实现协程调度,它只是“借力”Db 的协程能力。换言之,模型协程 = Eloquent + Db 协程。
-
事务必须用 DB::transaction():直接
$db->beginTransaction()+commit()在协程中极易出错,因为连接可能被其他协程复用。DB::transaction()内部会确保连接绑定当前协程,并自动处理回滚。 -
模型事件(如 creating)默认在协程中触发,但事件监听器内仍需遵守协程规范(不能用
sleep、mysql_connect等)。
一句话总结
Db 协程是“能跑起来的发动机”,模型协程是“装了这台发动机的整车”——车看起来更高级、更易开,但真正让它不堵车的,还是底下那台协程化的引擎。


















