先更新数据库还是先删除缓存

422 阅读5分钟

# 缓存和数据库一致性问题,看这篇就够了---非常好的文章,推荐

“先更新数据库,后删除缓存”和“先删除缓存,后更新数据库”是两种常见的数据库与缓存同步策略。它们的主要区别在于执行顺序,且每种策略都有其优缺点。下面我们从一致性、性能、和实际应用的角度对这两种策略进行详细对比。

1. 先更新数据库,后删除缓存

方案描述:

  • 步骤 1:更新数据库。
  • 步骤 2:删除缓存。

优点:

  • 数据一致性:由于先更新数据库,缓存失效之后的下一次请求会直接从数据库读取数据,确保缓存的数据是最新的。即便缓存删除失败,数据库中的数据始终是最新的。
  • 较少的缓存污染:如果更新数据库失败,缓存数据并未删除,因此不会出现缓存存储过时数据的情况。缓存中的数据依然有效,避免了误删除缓存后的缓存穿透问题。

缺点:

  • 数据库更新延迟:在多线程并发的情况下,线程 A 可能先读取了旧值(缓存中),但在数据库更新成功之前,如果线程 B 更新了数据库并删除了缓存,线程 A 会把旧值写入缓存。尽管在大多数情况下这个概率很低,但仍然是潜在的风险。
  • 性能瓶颈:由于更新数据库是一个阻塞操作,尤其在事务性数据库中,可能会造成性能瓶颈,导致写操作需要等待锁或事务完成。

适用场景:

  • 数据库操作较为频繁且需要保证一致性,且缓存更新时不希望缓存中有错误数据的场景。
  • 写操作较少,读操作较多,因此数据库更新操作不会频繁影响缓存一致性。

2. 先删除缓存,后更新数据库

方案描述:

  • 步骤 1:删除缓存。
  • 步骤 2:更新数据库。

优点:

  • 避免缓存污染:由于先删除缓存,缓存中的数据不再存在,后续的读请求会直接到数据库获取数据。这意味着即使缓存更新失败,也不会有过时数据被读取到缓存中。
  • 缓存穿透问题较少:如果缓存被删除之后,数据直接从数据库中读取,避免了由于缓存不一致而引发的缓存穿透问题。

缺点:

  • 数据一致性问题:删除缓存之后,如果数据库更新操作失败,可能会导致数据库与缓存数据不一致。例如,缓存中没有数据,但数据库未能正确更新,那么下一次读取数据库后再填充缓存时,会写入错误的数据。
  • 数据库的临时不一致性:由于缓存已被删除,读取请求会直接访问数据库,导致读取到旧数据。即使数据库操作最终成功,缓存可能会有短暂的时效性问题。此时,缓存会被填充为新的值,但在此期间数据库的数据可能是过时的。

适用场景:

  • 读写操作较为平衡,并且更新缓存操作不频繁,或使用了合适的缓存更新策略(如延迟更新、后台刷新等)来确保一致性。
  • 对数据库操作的失败有容错机制,例如通过重试机制来确保数据最终一致性。

对比总结

特性先更新数据库,后删除缓存先删除缓存,后更新数据库
数据一致性更好的一致性:缓存被删除后,数据库更新后才会写入缓存,减少旧数据写入缓存的风险。可能的数据不一致:删除缓存后数据库更新失败,导致数据库和缓存数据不一致。
缓存污染数据更新后缓存会保存最新数据,因此减少了缓存污染的风险。缓存会被删除,避免了缓存污染,但存在临时不一致的风险。
性能影响在多线程环境中,可能存在线程 A 写入旧数据到缓存的风险,性能受数据库锁的影响较大。数据库更新操作前,缓存已被删除,短期内可能造成性能瓶颈,但缓存污染问题少。
适用场景数据库操作频繁,读操作较多,需要避免缓存中存储错误数据。读写操作较平衡,对容忍临时不一致性和有较强容错机制的场景。

两者方案的优化

  • 先更新数据库,后删除缓存

    • 在多线程情况下,可以引入 锁机制,保证写数据库的操作是原子的。
    • 使用 事务 来确保数据库操作的一致性,避免出现部分成功的情况。
    • 配合使用 异步删除缓存队列机制 来减少延迟。
  • 先删除缓存,后更新数据库

    • 可以通过 重试机制补偿机制 来确保数据库更新失败时的数据恢复。
    • 引入 乐观锁版本控制 来避免缓存和数据库的冲突。
    • 通过 后台刷新机制,定期从数据库同步数据到缓存,避免短期内的缓存穿透问题。

总结

  • 先更新数据库,后删除缓存 更适合对数据一致性要求较高的场景,尤其是缓存更新频繁且对缓存中数据要求严格一致的情况。
  • 先删除缓存,后更新数据库 适合对性能要求较高且缓存更新相对不频繁的场景,尤其是能够容忍短暂的不一致性的情况。