多态模型中如何实现单用户单条访问记录的存储与更新
用户单条访问会话记录同步更新实现方案
原有方案的核心逻辑缺陷
- 第一版代码问题:存在两次冗余的visits表查询,分支判断逻辑冗余;只要用户存在任意一条访问记录,就执行对该用户下所有访问记录的全局更新,一旦历史遗留多条用户访问的脏数据,会出现批量更新的异常,且没有从根本上保证每个用户仅存一条记录的约束。
- 第二版代码问题:
updateOrCreate的匹配条件设置错误。该方法的第一个参数为查找已存在记录的匹配规则,原代码将visitable_id、visitable_type作为匹配条件,意味着系统仅会查找“和当前访问页面完全匹配的用户访问记录”,一旦用户切换访问页面,就无法匹配到之前的旧记录,直接触发新建操作,完全偏离需求;同时代码存在变量名混淆问题,将当前登录用户、被访问的目标页面模型统一命名为$user,极易出现字段赋值错位的低级bug。
正确实现代码
核心逻辑:使用updateOrCreate时,仅将user_id作为唯一的查找匹配条件,无论用户当前访问哪个页面,永远先定位属于该用户的那一条唯一访问记录,存在则同步更新访问页面的相关字段,不存在则新建记录。
if (auth()->check()) { $currentAuthUser = auth()->user(); $currentAuthUser->visits()->updateOrCreate( // 匹配规则:仅锁定当前登录用户的唯一一条会话记录,不绑定访问页面维度的条件 ['user_id' => $currentAuthUser->id], // 匹配到已有记录时,需要同步更新的访问状态字段 [ 'visitable_id' => $visitedModel->id, 'visitable_type' => get_class($visitedModel) ] ); }
配套优化建议
- 数据库层硬约束:给
visits表的user_id字段添加唯一索引,从数据库层面杜绝同一用户生成多条访问记录的可能,从根源上避免脏数据。 - 语义优化:使用
auth()->check()做登录状态判断,替代原有的auth()->user()判空写法,语义更清晰,减少不必要的用户对象加载。 - 时间戳适配:依赖模型默认开启的自动时间戳功能,每次更新/创建记录时会自动维护
created_at、updated_at字段,刚好适配“展示用户最近访问状态”的动态feed需求,无需手动写入时间字段。
内容的提问来源于stack exchange,提问作者user123
相关产品推荐
相关产品推荐

