为什么需要延迟双删,两次删除的原因是什么?
延迟双删的基本流程
- 首次删除缓存
- 更新数据库
- 二次删除缓存
示例代码实现:
@Service
public class ProductService {@Autowiredprivate StringRedisTemplate redisTemplate;private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();public void updateProduct(Product product) {deleteCache(product.getId()); // 第一次删除缓存updateProductInDB(product); // 更新数据库scheduler.schedule(() -> deleteCache(product.getId()), 2, TimeUnit.SECONDS); // 延迟二次删除}
}
首次删除缓存的原因
- 若先更新数据库再删缓存,当缓存删除失败时会导致数据不一致
- 先删缓存后更新数据库的方案更优:
- 若删除成功但更新失败,仅产生缓存缺失而非数据错误
- 数据库操作比缓存操作更容易失败
- 更新操作比删除操作更容易失败
对于低并发场景,单次删除通常已能满足需求。但在高并发时可能出现问题:首次删除缓存会放大读写并发导致的数据不一致风险。
解决方案 - 延迟双删: 通过写线程在执行"删缓存→更新数据库"后,延迟1-2秒再次删除,可有效清除可能被读线程写入的脏数据。此方案虽可能导致有效缓存被清除,但仅增加一次cache miss,影响有限。
既然有第二次删除,第一次删除是否必要?
完全必要。若取消首次删除,流程简化为:
- 更新数据库
- 删除缓存
此时若第二步失败将直接导致数据不一致。而延迟双删中:
- 首次删除降低基础不一致风险
- 二次删除专门处理并发场景下的不一致 即使二次删除可能失败,但整体方案显著降低了不一致概率。当然,在低并发场景中,根据实际情况简化方案也是可行的。