Skip to content

缓存更新

缓存更新

三种模式对比:

模式名称数据库与缓存一致性性能可靠性特点
Cache Aside 缓存到旁边最终一致简单易实现,适合读多写少场景
Read/Write Through 读/写强一致所有操作都通过缓存代理数据库
Write Behind 后写最终一致延迟写入数据库,性能高但复杂

Cache Aside 模式-旁路缓存

原理:

  • 读取时:先查缓存,缓存没有则查数据库,并将结果写回缓存。
  • 写入时:直接更新数据库,同时删除或更新缓存。

适用场景:

  • 读多写少
  • 对一致性要求不高,可接受短暂不一致

查询:

查询流程

更新数据

更新数据

代码流程:

java
public class CacheAsideExample {

    private final RedisTemplate<String, String> redisTemplate;
    private final DataDao dataDao;

    public CacheAsideExample(RedisTemplate<String, String> redisTemplate, DataDao dataDao) {
        this.redisTemplate = redisTemplate;
        this.dataDao = dataDao;
    }

    // 读取数据(优先从缓存)
    public String getData(String key) {
        try {
            String cached = redisTemplate.opsForValue().get(key);
            if (cached != null) {
                return cached;
            }

            String dbData = dataDao.getFromDB(key);  // 查询数据库
            if (dbData != null) {
                redisTemplate.opsForValue().set(key, dbData, 60, TimeUnit.SECONDS);  // 写入缓存
            }
            return dbData;
        } catch (Exception e) {
            // 记录日志或降级处理
            return dataDao.getFromDB(key);  // 可选降级方案
        }
    }

    // 更新数据(更新数据库 + 删除缓存)
    public void updateData(String key, String newValue) {
        try {
            dataDao.updateDB(key, newValue);       // 更新数据库
            redisTemplate.delete(key);             // 删除缓存
        } catch (Exception e) {
            // 日志记录或补偿机制
        }
    }
}

Read / Write Through 模式-读穿 / 写穿

原理:

  • 所有读写请求都经过缓存层。
  • 如果缓存中没有数据,由缓存组件自动从数据库加载。
  • 写操作时,缓存和数据库同步更新。

这种模式常用于封装了缓存逻辑的服务层(如使用 Spring Cache 或 Caffeine),也可以自己实现。

适用场景:

  • 要求缓存和数据库强一致性
  • 不希望业务代码处理缓存细节

查询:

与CahcheAside模式一致

更新数据:

无标题-2025-07-15-1145 (2)

代码流程:

java
ublic class CacheService {

    private final RedisTemplate<String, User> redisTemplate;
    private final UserMapper userMapper;

    public CacheService(RedisTemplate<String, User> redisTemplate, UserMapper userMapper) {
        this.redisTemplate = redisTemplate;
        this.userMapper = userMapper;
    }

    //  Read Through:读取用户信息
    public User getUserById(Long userId) {
        String cacheKey = "user:" + userId;

        // 先查缓存
        User user = redisTemplate.opsForValue().get(cacheKey);
        if (user == null) {
            // 缓存未命中,查询数据库
            user = userMapper.selectById(userId);
            if (user != null) {
                // 写入缓存
                redisTemplate.opsForValue().set(cacheKey, user, 60, TimeUnit.SECONDS);
            }
        }
        return user;
    }

    // Write Through:更新用户信息
    public void updateUser(User user) {
        String cacheKey = "user:" + user.getId();

        // 同步更新数据库
        userMapper.update(user);

        // 同步更新缓存
        redisTemplate.opsForValue().set(cacheKey, user, 60, TimeUnit.SECONDS);
    }
}

Write Behind 模式-异步写入 / 回写

原理:

  • 写操作只更新缓存,标记为“脏”。
  • 后台线程定期将“脏”数据批量写入数据库。
  • 优点是高性能,缺点是可能丢失数据。
  • 在 Write Behind 模式中,缓存是主数据源,数据库只是最终持久化的目标。

适用场景:

  • 对性能要求极高
  • 可容忍一定数据丢失风险

查询:

与CacheAside一致

更新数据:

无标题-2025-07-15-1145 (3)

代码流程:

java
public class WriteBehindCache {

    private final Map<String, String> cache = new ConcurrentHashMap<>();
    private final Map<String, String> writeQueue = new ConcurrentHashMap<>();
    private final Database database;
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    public WriteBehindCache(Database database) {
        this.database = database;
        scheduleFlush();
    }

    public void set(String key, String value) {
        cache.put(key, value);
        writeQueue.put(key, value);  // 加入待写队列
    }

    public String get(String key) {
        return cache.getOrDefault(key, "Not Found");
    }

    private void scheduleFlush() {
        scheduler.scheduleAtFixedRate(this::flushToDatabase, 5, 5, TimeUnit.SECONDS);
    }

    private void flushToDatabase() {
        for (Map.Entry<String, String> entry : writeQueue.entrySet()) {
            database.updateDB(entry.getKey(), entry.getValue());  // 模拟写入 DB
        }
        writeQueue.clear();  // 清空队列
    }
}

对比

模式名称数据库与缓存一致性性能可靠性特点
Cache Aside 缓存到旁边最终一致简单易实现,适合读多写少场景
Read/Write Through 读/写强一致所有操作都通过缓存代理数据库
Write Behind 后写最终一致延迟写入数据库,性能高但复杂
最近更新