Databases 17 min read

How to Keep Cache and Database Consistent: 4 Common Strategies and Their Pitfalls

This article examines the double‑write consistency problem between databases and caches like Redis, explains why naïve cache‑first or DB‑first updates can cause stale or phantom data under high concurrency, and evaluates four practical solutions with detailed trade‑offs and recommended retry mechanisms.

IT Services Circle
IT Services Circle
IT Services Circle
How to Keep Cache and Database Consistent: 4 Common Strategies and Their Pitfalls

Introduction

Database‑cache double‑write consistency is a language‑agnostic issue that becomes critical in high‑concurrency scenarios. When a record is updated in the database but the cache is not refreshed correctly, stale data may be served to users.

Common Cache Usage Pattern

User request checks the cache first; if present, the cached value is returned.

If the cache misses, the database is queried.

When the database returns data, it is written into the cache and then returned to the user.

At first glance this flow seems safe, but it ignores the case where a database row is updated immediately after being cached.

If the database row changes after it has been cached, the cache must be updated; otherwise users may read outdated values.

Four Practical Solutions

1. Write Cache First, Then Database

In this approach the cache is updated before the database. If a network failure occurs after the cache write but before the database write, the cache contains a value that does not exist in the database, leading to a "dirty cache" problem.

Because the cache would hold a 假数据 (fake data), this method is generally unsuitable for production.

2. Write Database First, Then Cache

Here the database is updated first, followed by a cache write. This avoids the dirty‑cache scenario, but introduces new issues:

If the cache write fails, the database holds the new value while the cache still contains the old value, causing inconsistency.

In high‑concurrency environments, two concurrent writes (a and b) can interleave such that the later cache write overwrites the newer database value with an older one.

The extra cache write consumes CPU and memory resources, especially when the cached value requires expensive computation.

3. Delete Cache First, Then Write Database

Instead of updating the cache, the cache entry is deleted before the database write. However, this still suffers from race conditions: a concurrent read may repopulate the cache with stale data before the delete completes.

To mitigate this, a cache‑double‑delete strategy is used: delete the cache before the DB write and delete it again after a short delay (e.g., 500 ms) to ensure any stale repopulation is removed.

4. Write Database First, Then Delete Cache

This method deletes the cache after the database update. It reduces the window where stale data can be read, but if the delete fails, inconsistency remains.

When a delete fails, a retry mechanism is required. Common retry tactics include:

Immediate synchronous retries (e.g., three attempts).

Asynchronous retries using a dedicated thread.

Submitting a retry task to a thread pool (risk of loss on server restart).

Recording the retry in a database table and using a scheduled job (e.g., Elastic‑Job) to retry.

Publishing a message to a message queue for later processing.

Retry Mechanisms for Cache Deletion Failures

If the cache deletion fails after a successful DB write, the system should attempt up to three synchronous retries. If all attempts fail, the operation is recorded for later handling.

For high‑throughput services, asynchronous retries are preferred. Options include:

Creating a dedicated retry thread (may cause OOM under heavy load).

Using a thread pool (risk of loss on restart).

Storing retry data in a table and processing it with a scheduled job.

Sending a retry message to a message queue.

Scheduled Task Retry

A scheduled task can periodically read the retry table, attempt to delete the cache up to five times, and mark the record as failed after exhausting retries. Elastic‑Job is recommended for its sharding capabilities and flexible interval settings.

Message Queue (MQ) Retry

When a cache delete fails, a message can be sent to an MQ (e.g., RocketMQ). The consumer retries the delete up to five times; if still unsuccessful, the message is moved to a dead‑letter queue for manual intervention. MQ‑based retries provide higher real‑time performance than scheduled tasks.

Binlog‑Based Cache Invalidation

Instead of handling cache invalidation in the application code, a binlog subscriber (e.g., Canal) can listen to MySQL binlog events. After the DB write, the subscriber deletes the corresponding cache entry. If the delete fails, the subscriber can publish an MQ message for automatic retries, combining the simplicity of binlog‑driven invalidation with robust retry handling.

Overall, the "write database then delete cache" strategy, complemented by a reliable retry mechanism (scheduled task, MQ, or binlog + MQ), offers the lowest probability of cache‑database inconsistency among the discussed approaches.
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

databaseRedishigh concurrencyCache Consistencyretry mechanismswrite strategies
IT Services Circle
Written by

IT Services Circle

Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.