精准删除和全量删除理解

27 阅读3分钟

这是一个非常好的切入点。要理解为什么有的操作是“精准删除”,有的操作是“全部删除”,我们需要先回顾一下C端(用户端)是如何查询套餐缓存的

1. 缓存的存储结构(核心前提)

在C端(用户浏览页面),套餐是**按照“分类”**来进行缓存的。

  • Key的格式setmealCache::分类ID

  • 举例

    • 分类ID=100(超值套餐):Redis里存的是 setmealCache::100 -> [套餐A, 套餐B...]
    • 分类ID=200(儿童套餐):Redis里存的是 setmealCache::200 -> [套餐C, 套餐D...]

理解了这个前提,我们再来看那几个接口的处理逻辑:


2. 为什么 save (新增) 是精准删除?

Java

@CacheEvict(cacheNames = "setmealCache", key = "#setmealDTO.categoryId")
  • 场景:你要在“超值套餐(ID=100)”这个分类下,新增一个“牛肉汉堡套餐”。

  • 逻辑

    1. 前端传过来的 setmealDTO 里明确包含了 categoryId = 100
    2. 后端非常清楚:只有“超值套餐”这个分类的数据变了,其他“儿童套餐”、“饮料”等分类的数据没受影响。
    3. 决策:所以我只需要精准删掉 setmealCache::100 这一条缓存即可。
  • 优点:影响范围小,效率高。


3. 为什么 delete, update, startOrStop 是全量删除?

Java

@CacheEvict(cacheNames = "setmealCache", allEntries = true)

这里使用 allEntries = true(删除 setmealCache 下的所有 key),主要是出于实现成本数据一致性的考量。

原因一:入参信息不足(针对 delete 和 startOrStop)

  • 场景:你要删除 ID=5 的套餐,或者停售 ID=5 的套餐。

  • 参数:前端只传了一个 ids=5 或者 id=5

  • 问题代码不知道这个 ID=5 的套餐属于哪个分类!

    • 如果不查数据库,我根本不知道该删 setmealCache::100 还是 setmealCache::200
    • 如果为了删缓存,先去查一次数据库找分类ID,又多了一次数据库IO,得不偿失。
  • 决策:干脆把所有套餐缓存都清空,反正下次用户查的时候会重新加载,这样代码最简单,也不会出错。

原因二:存在“修改分类”的复杂情况(针对 update)

  • 场景:你要修改一个套餐。

  • 复杂逻辑

    • 假设“牛肉套餐”原本属于“超值套餐(ID=100)”。
    • 管理员把它改到了“今日推荐(ID=300)”。
  • 问题

    • 如果你只删除了新分类(ID=300)的缓存,那么旧分类(ID=100)的缓存里可能还残留着这个套餐数据(脏数据)。
    • 要想精准清除,你得知道它修改前是哪个分类,这又需要查数据库比对。
  • 决策:为了防止这种跨分类修改导致的数据不一致,直接清空所有缓存是最安全的做法。


4. 总结:这是一种“用性能换简单”的权衡

操作难度为什么这么做?
新增简单我手里正好有 categoryId,顺手把它对应的缓存删了,精准又高效。
删除/起停困难我手里只有 id,不知道 categoryId。为了不查库,索性全删了。
修改复杂套餐可能从一个分类跳到另一个分类,为了防止旧分类留有脏数据,索性全删了。

这种做法在生产环境有问题吗?

在“外卖点餐”这种场景下,完全没问题。

  1. 读多写少:用户查几万次,管理员才改一次。
  2. 重建快:就算把缓存全删了,用户并发查进来,也只是多查几次数据库,很快就又缓存上了。
  3. 安全性:数据一致性大于微小的性能损耗。全删能100%保证用户不会看到错误的数据。