sync()仅适用于多对多关系的中间表批量更新,会清空旧记录再写入新数据;在hasOne、belongsTo或hasMany关系上调用将报错;支持带额外字段的写入但不触发模型事件,Laravel 9+起可监听pivot事件。
Sync 方法不是万能的数据同步工具,它只适用于多对多关系的中间表数据批量更新,且会清空原有记录再写入新数据。
sync() 只作用于多对多关系(pivot 表)
如果你在
、
或
关系上调用
,会直接报错:
。Laravel 的
是
关系专属方法,底层依赖中间表(pivot table)的存在。
常见使用场景:
用户分配多个角色(
↔
,中间表
)
文章打多个标签(
↔
,中间表
)
商品关联多个分类(需确保是多对多建模,而非单向外键)
sync() 会删除不在数组中的旧关联
调用
的实际行为是:先删掉该用户当前所有角色记录,再插入 ID 为 1、3、5 的三条新记录。它不比对差异,也不保留历史 —— 这是和
/
最本质的区别。
如果只想新增不删旧,改用:
(跳过已存在项)
(Laravel 5.8+,保留已有,仅追加缺失)
注意:
仍可能触发重复插入异常(如中间表有唯一索引),需确保数据幂等或提前去重。
Laravel 13.2.0
PHP中文网提供Laravel 13.2.0版本下载,Laravel框架 是基于 PHP 8.3+ 的高性能框架,官方推荐通过 Composer 安装。它内置 AI SDK、JSON:API Resources 及原生向量搜索,支持属性驱动开发与队列路由,大幅提升开发效率。相比旧版,13.2.0 优化了缓存 TTL 管理与实时通信,无需 Redis 即可横向扩展。作为现代 Web 开发首选,它兼顾安全与极速体验,助您快速构建企业级应用。
下载
sync() 支持带额外字段的批量写入
当 pivot 表含额外字段(如
、
、
),可传入关联数组:
未显式指定的字段将设为 null(除非数据库默认值生效)。若想让某些字段保持原值(如更新时间戳),
本身不支持 —— 此时应放弃
,改用
或手动分步处理(
+
+
)。
sync() 不触发模型事件,但会触发 pivot 事件(Laravel 9+)
默认情况下,
不会触发
、
等模型事件,因为操作对象是 pivot 记录,而非主模型。但从 Laravel 9 开始,可通过监听
、
、
等
事件捕获
中间表变更。
容易忽略的点:
事务安全:若 sync 失败(如外键约束失败),整个操作回滚,但不会自动包装在事务里 —— 你得自己用
性能影响:大批量 sync(如上万 ID)会导致中间表频繁 DELETE + INSERT,建议拆分批次或改用原生 SQL
软删除关联:如果 pivot 表用了软删除(如
),
默认不恢复已软删记录 —— 需配合
或自定义逻辑
真正需要“同步”业务逻辑时,别迷信
—— 先确认是不是多对多,再判断要不要清旧,最后看字段和事件是否满足需求。一步写错,中间表就丢了历史。
hasOnebelongsTohasManysync()Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::sync()sync()BelongsToManyusersrolesrole_userpoststagspost_tag$user->roles()->sync([1, 3, 5])attach()detach()$user->roles()->attach([2, 4])$user->roles()->syncWithoutDetaching([1, 3, 5, 2, 4])syncWithoutDetachingcreated_bypriorityexpires_at$user->roles()->sync([
1 => ['assigned_at' => now(), 'notes' => 'admin setup'],
3 => ['assigned_at' => now()->subDay(), 'notes' => 'temp access'],
]);sync()sync()upsert()detachattachupdateExistingPivotsync()creatingupdatingPivotAttachedPivotDetachedPivotToggledDB::transaction()deleted_atsync()withTrashed()sync()