Laravel 9 中 increment() 不支持同时更新其他字段,推荐用 update() 配合 DB::raw 实现原子性自增与多字段更新;次选 touch() 或 fill()->save() 分步操作,但非原子;避免重写源码或拼接原生 SQL。

Laravel 9 中使用 Eloquent 的 increment() 方法时,默认只更新指定字段的值(加一或加指定数值),**不支持直接在同一个查询中同时修改其他字段**。但有几种简洁、安全且符合 Laravel 风格的写法来实现“自增 + 同时更新其他字段”的需求。
✅ 推荐方式:用 update() 手动计算并更新
这是最清晰、可控性最强的方式,尤其适合需要原子性(避免并发问题)且逻辑明确的场景。
- 先查出当前值(可选,仅当后续逻辑依赖原值时才需要)
- 用
update()一次性设置自增字段(用 DB::raw)和其他字段
示例:给用户积分 +1,同时更新最后签到时间
$user->update([
'points' => DB::raw('points + 1'),
'last_sign_in_at' => now(),
]);
✅ 优势:单条 SQL、原子执行、可扩展(比如加 5 分、更新多个字段)、兼容所有数据库。
✅ 替代方案:用 increment() 后链式调用 touch() 或 fill()->save()
如果只是顺带更新时间戳或少量字段,且不强求严格原子性(即允许两步操作),可以分步写:
-
increment('points')返回影响行数,再调用touch()更新updated_at(或自定义时间字段) - 或者用
fill()+save()显式赋值(注意会触发模型事件和类型转换)
示例:
$user->increment('points'); // points + 1
$user->touch('last_sign_in_at'); // 只更新 last_sign_in_at 字段
⚠️ 注意:这不是原子操作,中间若失败可能导致数据不一致;touch() 只支持时间戳字段(默认 updated_at,或传参指定)。
❌ 不推荐:重写 increment() 或拼接 raw SQL
Eloquent 的 increment() 内部调用的是 Builder::increment(),它底层是 DB::raw + update(),但**不开放多字段扩展接口**。强行改源码或手动拼 SQL 容易出错、难维护、绕过模型逻辑(如访问器、强制类型、事件等)。
? 小技巧:封装成模型方法复用
把常用组合逻辑封装进模型,提升可读性和复用性:
// 在 User 模型中
public function incrementPointsAndRefreshSignIn()
{
return $this->update([
'points' => DB::raw('points + 1'),
'last_sign_in_at' => now(),
]);
}
调用:$user->incrementPointsAndRefreshSignIn();


















