
模型字段自动更新热度值用什么钩子
ThinkPHP 没有内置“标签热度”概念,得自己在模型写逻辑。最稳的方式是用 afterWrite 钩子——它在数据插入或更新成功后触发,能确保主键已生成、事务已提交,避免因并发或回滚导致统计错乱。
beforeWrite 不行:此时数据还没落库,万一失败,热度就白加了afterRead 更不行:每次查都加一次,直接把热度刷爆如果只统计“被搜索/被点击”类行为,建议单独建日志表+异步聚合,别在核心模型里硬塞
怎么安全地给标签字段加热度计数
别直接 $model->save([‘hot’ => $model->hot + 1]) —— 这会覆盖其他字段,且在并发下大概率出错。要用数据库自增语句,靠 DB 层原子性保安全。
推荐用 Db::name(‘tag’)->where(‘id’, $id)->inc(‘hot’)->update()如果必须走模型,用 $model->where(‘id’, $id)->setInc(‘hot’)(注意不是 save())字段类型必须是 INT 或 BIGINT,别用 DECIMAL 或字符串存数字初始值设为 0,别留 NULL,否则 setInc 在某些版本会报错
热度排序时 order(‘hot desc’) 为什么不准
因为默认没加索引,数据一多就慢,而且 MySQL 的 ORDER BY 在无索引时可能返回非确定顺序,尤其配合 LIMIT 时容易漏掉同热度的记录。
立刻加索引:ALTER TABLE `tag` ADD INDEX idx_hot (hot);如果热度变化频繁,考虑把 hot 和 id 组合索引:ADD INDEX idx_hot_id (hot, id),避免回表别用 order(‘hot desc’)->limit(10) 直接取“最热10个”——同热度标签可能被随机截断,应加二级排序,比如 order(‘hot desc, id desc’)
缓存热度值要不要加时间戳校验
要。ThinkPHP 的 cache() 默认不带过期逻辑,直接缓存 hot 字段值会导致前端看到的永远是旧数据。
立即学习“PHP免费学习笔记(深入)”;
读热度时用 cache(‘tag_hot_’.$id, null, 3600),显式设 1 小时过期更新热度后,务必清对应缓存:cache(‘tag_hot_’.$id, null)别缓存整个模型对象——hot 变化快,其他字段不变,缓存粒度太粗反而拖慢更新效率Redis 作缓存时,注意 setInc 后没同步回缓存,所以读缓存、写 DB、删缓存三步不能少
热度统计本身不难,难的是在高并发下不出错、不拖慢主流程、不和缓存对不上。每一步都要想清楚:这行代码是在 DB 里执行,还是 PHP 里算,还是缓存里读——混在一起就容易漏掉原子性或一致性。

评论(0)