increment是最安全的自增方式,直接在数据库层执行加法避免并发覆盖;需传字段名和可选步长,支持条件更新与多字段联动,但不触发模型事件、不刷新内存值,返回受影响行数。

increment 方法怎么用才不丢数据
直接调用 increment 是最安全的自增方式,它在数据库层面完成加法,避免了「读-改-写」导致的并发覆盖。别用 $post->views++ 再 save(),那会漏掉并发请求的计数。
- 必须传入字段名,如
increment('views');支持第二个参数指定步长,默认是 1 - 可以连带更新其他字段,比如
increment('views', 1, ['updated_at' => now()]) - 不触发模型的
updating/updated事件,如果依赖这些事件做日志或缓存清理,得手动补 - 返回的是受影响行数(int),不是模型实例,别链式调用
->fresh()之类
Laravel 10+ 中 increment 的兼容性注意点
从 Laravel 9 升到 10 后,increment 对 PostgreSQL 的默认行为变了:以前会自动把 null 转成 0 再加,现在直接报错 SQLSTATE[22004]: Null value not allowed。
- MySQL/SQLite 仍兼容 null → 0 的隐式转换
- PostgreSQL 必须确保字段有默认值(如
default(0))或提前初始化为 0 - 保险做法是先检查:用
whereNotNull('views')+orWhere('views', 0)双条件兜底
带条件的点击量自增(防刷、去重)
真实场景里不能无脑 +1,得限制同一 IP 或用户一天只能算一次。这时 increment 要配合 where 使用,且逻辑必须放在数据库层判断。
- 用
where('ip_address', request()->ip())->whereDate('viewed_at', today())锁定条件 - 别在 PHP 层查一遍再决定是否
increment,否则仍有竞争窗口 - 注意:如果条件不匹配,
increment返回 0,不是报错——要靠返回值判断是否真增了 - IP 字段建议加索引,否则 where 查询变全表扫描,高并发下拖慢整个自增流程
为什么不用 update + DB::raw('views + 1')
语法上可行,但没必要绕路。原生 DB::raw 在这里没优势,反而容易出错。
-
increment自动处理字段类型、空值、驱动差异(比如 SQL Server 的+=写法) -
DB::raw('views + 1')在 SQLite 下可能因类型亲和性导致字符串拼接,比如 '9' + 1 = '91' - 如果字段是 unsigned,
DB::raw不会校验溢出,而increment在 PDO 层会抛异常 - 调试时看 query log,
increment生成的 SQL 更干净,一眼能看出意图
increment 不改内存里的模型属性,所以 $post->views 还是旧值。需要最新值就得自己再查,或者用 refresh(),别以为它像 save() 那样同步状态。











