model::create() 未写入数据库的首要原因是 $fillable 白名单为空、未定义或遗漏字段,导致批量赋值被静默过滤;其次需确认模型是否被正确加载、注解元数据是否刷新、数据库约束或事务是否中断。

Model::create() 什么都没写入数据库?先看 $fillable 是否为空或漏字段
Hyperf 的 Model::create() 默认走批量赋值流程,和 Laravel 一样受 $fillable 白名单严格控制。如果模型里 $fillable 是空数组、没定义、或漏了你要写的字段,create() 就会静默跳过对应字段 —— 不报错、不抛异常、也不写库,看起来就像“没生效”。
常见错误场景:
-
$fillable = [](比如视图模型误配)→ 所有字段被拒 -
$fillable = ['id', 'name'],但实际传了['name', 'email', 'status']→ 只有name被写入 - 字段名大小写/下划线不一致:数据库是
user_name,却在$fillable写成userName→ 不匹配,被过滤
验证方法:临时加一行 dd($model->getFillable()); 看输出是否包含你传的键名。别依赖 IDE 自动补全,手敲确认。
为什么加了 $fillable 还失败?检查模型是否被正确加载和反射
Hyperf 在协程环境下依赖 DI 容器和注解扫描,如果模型类根本没被加载,create() 可能调用的是一个空壳或旧缓存版本。
必须确认以下几点:
- 模型文件路径是否在
config/autoload/annotations.php的scan.paths里?默认只扫BASE_PATH . '/app',若模型放在app/Model外(如Domain/User/ProfileModel.php),必须显式加入 - 改完
$fillable后有没有执行php bin/hyperf.php di:init-proxy?否则注解元数据未刷新,容器仍用旧规则 - 类名与文件名是否完全一致?
class UserProfile extends Model必须存于app/Model/UserProfile.php,大小写都不能错
一个快速验证方式:var_dump(class_exists(\App\Model\UserProfile::class)); 返回 false 就说明类根本没加载进来。
create() 返回 null 或空模型?可能是数据库约束或事务中断
create() 成功时返回新模型实例,失败时默认返回 null(不抛异常),容易被忽略。这通常不是模型配置问题,而是底层写入被拦住了。
排查方向:
- 数据库字段设了
NOT NULL但没传值,或长度超限(例如key字段定义为VARCHAR(15),但代码中substr(..., 0, 15)实际截出 16 字节 UTF-8 字符) - 唯一索引冲突:重复插入相同
key值,MySQL 报SQLSTATE[23000]: Integrity constraint violation,但 Hyperf 默认不把这类错误转为异常 - 当前协程里开启了事务但没提交,或上层 try/catch 吞掉了异常(尤其搭配
DB::transaction()时)
建议加一层保护:
try {
$model = UserKey::create($data);
if (! $model || ! $model->getKey()) {
throw new RuntimeException('Create failed: no primary key assigned');
}
} catch (\Throwable $e) {
\Log::error('UserKey create error', ['data' => $data, 'exception' => $e->getMessage()]);
throw $e;
}
想绕过 $fillable 直接写入?用 new + save() 更可控
当调试不确定白名单是否生效,或需要临时写入敏感字段(如测试用的 is_admin),直接 new 模型再 save() 是最透明的方式 —— 它不走批量赋值逻辑,所有属性都按字面量设置。
示例:
$model = new UserKey(); $model->key = 'ABCDE-FGHIJ-KLMNO'; $model->plan = 'Pro'; $model->created_at = now(); $result = $model->save(); // 返回 bool
注意:
-
save()不自动填充created_at/updated_at,除非模型启用了时间戳且字段存在 - 不会触发
creating或created事件,如需事件支持,得手动调用$model->fireModelEvent('creating', false) - 该方式适合调试和边界场景,上线代码仍应以
$fillable为准,避免安全风险
真正难排查的往往不是语法对错,而是模型类没被扫描、$fillable 被覆盖、或数据库约束在日志里一闪而过 —— 这些地方不打日志、不抛异常,就只能靠 dd() 和查询日志硬盯。











