Hyperf软删除模型正确绑定多库需三者协同:模型启用SoftDeletes、数据库存在deleted_at字段、运行时显式指定$connection;缺一将导致报错或查不到数据。

Hyperf 软删除模型要正确绑定多数据库连接,核心在于三者协同:模型声明、数据库字段、运行时连接指定必须严格匹配。不能只加 trait 就以为万事大吉,否则 delete() 会直接报错找不到 deleted_at 字段,或查询完全不返回软删数据。
模型需显式指定连接并启用 SoftDeletes
软删除模型必须同时满足两个前提:
- 在模型类中 use Hyperf\Database\Model\SoftDeletes;
- 设置 $connection 属性指向目标数据库连接名(如 'log_db'),不能依赖 default;
- 确保该连接对应的数据库表中存在 deleted_at 字段(类型为 DATETIME 或 TIMESTAMP,允许 NULL);
示例:
namespace App\Model;
use Hyperf\Database\Model\SoftDeletes;
use Hyperf\Database\Model\Model;
class Log extends Model
{
use SoftDeletes;
protected $connection = 'log_db'; // 关键:绑定到 log_db 连接
protected $table = 'logs';
}
软删除操作必须走指定连接
即使模型设了 $connection,以下写法仍可能失效:
-
Log::where('level', 'error')->delete()—— 正确,走 log_db; -
Db::table('logs')->where('level', 'error')->delete()—— 错误,走 default 连接,且不触发软删除逻辑; -
(new Log())->fill([...])->save()—— 实例方法不继承 $connection,需手动指定:(new Log())->setConnection('log_db')->save();
查询软删记录也需注意:
-
Log::withTrashed()->get()才能查出已软删的行; -
Log::onlyTrashed()->get()只查已软删的; - 这些方法都基于模型当前 $connection,若未设或设错,会查错库。
跨库关联与软删除的限制
软删除 + 多库场景下,关联模型不能自动跨连接生效:
- 假设 Log 属于 User,User 在 report_db,Log 在 log_db,两者物理隔离;
-
Log::with('user')->get()会失败——Eloquent 不支持跨连接 eager loading; - 必须分步查:先查 Log,再用 user_id 手动查 User 模型,并显式调用
User::on('report_db')->find(...); - 软删除状态仅对本库模型生效,无法通过关联自动过滤或还原对方库的软删状态。
事务中慎用软删除多库操作
Hyperf 的 Db::transaction() 只能绑定单一连接池:
-
Db::connection('log_db')->transaction(function () { ... })内部所有 Db 操作都强制走 log_db; - 不能在同一个事务里混合操作 log_db 和 report_db;
- 若需跨库一致性,需应用层补偿(如本地消息表 + 定时任务),Hyperf 不提供分布式事务协调能力。


















