Eloquent CRUD需配置$fillable/$guarded,否则create()静默失败;DB::table()返回stdClass,Model查询返回带访问器的实例;软删除需注意物理删除与级联;save()触发生命周期,update()直执行SQL;边界判断标准是是否需要模型层功能。

直接用 Eloquent 做 CRUD 最省心,但必须配好模型的 $fillable 或 $guarded,否则 create() 会静默失败——这是新手踩坑最多的地方。
模型必须声明可批量赋值字段
不设 $fillable,User::create([...]) 会返回空模型且不报错;Laravel 默认禁止所有字段批量赋值,这是安全机制,不是 bug。
-
$fillable = ['name', 'email', 'password']:白名单,只允许这些字段被create()或update()接收 -
$guarded = ['id', 'created_at']:黑名单,其余字段都允许(慎用,易留漏洞) - 如果字段含空格、连字符或特殊符号(如
first_name),确保它们在$fillable中原样写出,不能驼峰化
DB::table() 和 Model:: 查询行为差异
DB::table('users')->where('id', 1)->get() 返回的是 Illuminate\Support\Collection,每项是 stdClass 对象;而 User::where('id', 1)->get() 返回的是 Eloquent 集合,每项是 User 实例,自带访问器、修改器、关系加载能力。
- 需要链式调用
->with('posts')或触发getFullNameAttribute()?必须用模型查询 - 只读取数据、不做业务逻辑、追求极致性能(比如后台导出百万行)?用
DB::table()更轻量 -
DB::table()->insert()不触发模型事件(creating,saving),也不走boot()中定义的全局作用域
删除操作容易忽略软删除与外键约束
执行 User::find(5)->delete() 时,如果模型启用了软删除(use SoftDeletes),它不会真删,只是置 deleted_at;而 DB::table('users')->where('id', 5)->delete() 是物理删除,绕过所有 Eloquent 层逻辑。
- 硬删前务必确认是否关联了其他表:MySQL 外键设了
ON DELETE CASCADE时,Eloquent 不会自动级联,得手动写->withTrashed()或改用原生语句 - 批量删用
User::where('status', 'inactive')->delete(),别用->get()->each(...->delete()),后者会逐条查+逐条删,N+1 且慢 - 软删除记录默认不出现在
all()或get()结果里,要查包括已删的,加->withTrashed()
更新时别混淆 save()、update() 和 increment()
$user->name = 'Alice'; $user->save() 走模型生命周期(触发 saving、验证、事件);User::where('id', 1)->update(['name' => 'Alice']) 是直接 SQL UPDATE,跳过所有模型逻辑,也不加载模型实例。
- 需校验、加密、格式化字段(如密码哈希)?必须用实例 +
save() - 只改一个计数器字段(如
view_count)?用increment('view_count'),它生成UPDATE ... SET view_count = view_count + 1,线程安全 -
update()传入数组时,键名必须和数据库列名完全一致(区分大小写取决于 MySQL 配置),不能是模型访问器名(如full_name)
真正难的不是写对某一行代码,而是判断该用模型层还是查询构建器层——边界模糊时,先问自己:这步操作要不要触发事件、验证、访问器、关系预加载?要,就走模型;不要,就用 DB::table() 直达 SQL。


















