🔍搜索⌘K

后台删了奖品,缓存却一直没清掉

问题

我在一个抽奖活动后台里做奖品管理。后台改了奖品、或者把奖品下架删除的时候,得顺手把 Redis 里对应的缓存清掉——不然用户在抽奖端还能抽到已经下架的奖品,或者看到的库存还是旧数字。

现象

代码里删除的回调看着没毛病:拿到刚删的那条奖品记录,取出它属于哪个活动,然后用活动 id 拼出缓存 key,调 Cache::forget 和 Redis 的 zrem 把库存集合清掉。

可实际跑起来,删了奖品之后,抽奖端偶尔还是能抽到它,库存数对不上。更要命的是,这个 bug 一直没人发现——因为代码”看着是对的”,而且抽奖端大多数时候没出错,只是偶尔。

怎么解决

我怀疑是缓存根本没清掉,就进去查。关键在这一行:删除回调里取活动 id,用的是框架传给回调的那个”模型对象”。

查下来发现,框架在走删除流程时,内部是用 findOrFail([id]) 这种数组形式去查的,查回来的是一个集合,再被包成一个 Fluent 对象。这个 Fluent 对象身上,标量字段全都取不到——它只认一个叫 0 的键,真正的数据藏在 ->0 里面。所以我在回调里写 $model->event_configs_id,永远拿到的就是 null。

null 拼进缓存 key 里,Cache::forget 清的就不是真正的 key,而是裸前缀;zrem 同理也用错了 key。等于清了个寂寞。

修起来也简单:在删除回调里别依赖那个包装对象,直接拿 id 去数据库查这条奖品属于哪个活动,再拿活动 id 去清缓存。这样不管是单条删还是批量删,参数形态怎么变都不影响。

结论

别默认”框架回调里给的模型字段一定能取到”。批量删除和单条删除,回调拿到的参数形态未必一样,有些框架还会把结果包成集合再套一层对象,取标量字段就会踩空。

凡是涉及缓存失效的地方,最好单独写个测试,断言缓存真的被删了。这种”代码看着对、实际没生效”的不声不响的 bug,靠肉眼 review 很难抓出来,得靠测试接住。