Springboot中使用Redis作缓存

缓存(Cache)是数据交换过程中的缓冲区,通常被称为数据缓冲区。它通常从数据库中获取数据,并将其存储在本地代码中,以提高访问速度和系统性能。对于那些被频繁访问的热点数据,缓存可以显著减少对后端数据库的访问压力,从而降低响应时间(例如,数据库如 MySQL 通常存储在磁盘中,而 Redis 则存储在内存中),提升系统的整体吞吐能力和稳定性。本文介绍了两种redis缓存的实现方式,一种是直接手动操作redis,另一种是使用SpringCache。

一、用 Redis 作缓存的一个简易流程如下

1.1 数据读取流程(查询缓存)
  1. 客户端发起请求:用户通过客户端向应用服务器发送数据请求
  2. 缓存检查:应用服务器首先检查Redis缓存中是否存在所需数据
  3. 缓存命中路径
    • 如果缓存中有数据(缓存命中)
    • 直接从Redis获取数据
    • 立即返回缓存数据给客户端
  4. 缓存未命中路径
    • 如果缓存中没有数据(缓存未命中)
    • 查询数据库获取原始数据
    • 将查询到的数据写入Redis缓存
    • 为缓存数据设置过期时间(可选,一般像是验证码之类的就会设置)
    • 返回数据库数据给客户端
1.2 数据更新流程
  1. 数据更新请求:当需要修改数据时,首先更新数据库
  2. 缓存同步策略:更新数据库后需要处理缓存一致性,这里提供两种简单策略:
    • 删除策略:直接删除Redis中的相关缓存,下次查询时重新加载
    • 更新策略:同时更新Redis缓存中的数据,保持数据同步
  3. 完成更新:无论采用哪种策略,最终完成数据更新操作
1.3 用 Redis 作缓存的一个简易流程图如下所示
缓存命中
缓存未命中
删除策略
更新策略
客户端请求
应用服务器
检查Redis缓存
从Redis获取数据
查询数据库
返回缓存数据
获取数据库数据
将数据写入Redis缓存
设置过期时间
返回数据库数据
响应客户端
数据更新请求
更新数据库
缓存策略
删除Redis缓存
更新Redis缓存
完成更新

二、实现

以springboot项目为例(该springboot就包含简单的User增删改查),代码目录结构如下:

在这里插入图片描述
数据库User表结构图如下所示
在这里插入图片描述

2.1 手动用Redis实现(采用删除策略)
2.1.1 查询方法。先查缓存,命中直接返回,未命中就查数据库,然后将数据放入缓存再返回。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.1.2 新增用户、删除用户、更新用户信息,需要删除缓存。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.1.3 验证效果

一开始没有缓存

在这里插入图片描述

查询了ID为1的用户,缓存更新了

在这里插入图片描述

获取所有用户信息后的缓存情况

在这里插入图片描述

新增用户后,list缓存被删除了

在这里插入图片描述

更新ID为1的用户信息后,缓存里原key为1的缓存被删除了

在这里插入图片描述

2.2 使用SpringCache

**@Cacheable **方法执行前先检查缓存,如果缓存中有数据则直接返回,否则执行方法并将结果缓存。

// 根据ID查询用户,缓存key为用户ID
@Cacheable(value = "users", key = "#id")
public User getUserById(Long id) {
    return userMapper.selectById(id);
}

// 查询所有用户,缓存key为固定字符串
@Cacheable(value = "users", key = "'all'")
public List<User> getAllUsers() {
    return userMapper.selectList(null);
}

@CacheEvict 方法执行后删除指定的缓存数据。

// 删除指定用户的缓存
@CacheEvict(value = "users", key = "#id")
public boolean deleteUser(Long id) {
    return userMapper.deleteById(id) > 0;
}

// 删除所有用户相关缓存
@CacheEvict(value = "users", allEntries = true)
public void clearAllCache() {
    // 清空所有缓存
}

// 删除多个缓存
@Caching(evict = {
    @CacheEvict(value = "users", key = "#user.id"),
    @CacheEvict(value = "users", key = "'all'")
})
public boolean updateUser(User user) {
    return userMapper.updateById(user) > 0;
}

@CachePut 方法每次都会执行,并将结果更新到缓存中。

// 更新用户信息,同时更新缓存
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
    userMapper.updateById(user);
    return user; // 返回值会更新到缓存中
}

// 创建用户并缓存
@CachePut(value = "users", key = "#result.id")
public User createUser(User user) {
    userMapper.insert(user);
    return user;
}

@Caching 可以同时使用多个缓存注解,实现复杂的缓存操作。

// 组合使用:更新用户时,既要更新单个用户缓存,又要删除列表缓存
@Caching(
    put = @CachePut(value = "users", key = "#user.id"),
    evict = @CacheEvict(value = "users", key = "'all'")
)
public User updateUserAndRefreshCache(User user) {
    userMapper.updateById(user);
    return user;
}

// 删除用户时,删除多个相关缓存
@Caching(evict = {
    @CacheEvict(value = "users", key = "#id"),
    @CacheEvict(value = "users", key = "'all'"),
    @CacheEvict(value = "userDetails", key = "#id")
})
public boolean deleteUserWithDetails(Long id) {
    return userMapper.deleteById(id) > 0;
}

三、总结

springcache适合一些简单的缓存操作,比较方便,但是粒度相对比较粗;而手动实现的话,可以做到更细粒度,比如要针对删除符合某些复杂条件的缓存springcache就不好弄了,手动实现的却可以。

相关代码放在了https://gitee.com/tzm-hua/redis-cache中,其中manual分支为手动实现redis,springcache分支为使用springcache。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值