Redis 从入门到实战:SpringBoot 整合与 Cache 缓存应用
Redis 作为当前最流行的高性能键值对缓存数据库,凭借其快速度、多数据类型支持、分布式友好等特性,成为后端开发中缓存、会话存储、消息队列等场景的必备工具。本文将从 Redis 基础入门,逐步讲解其在 SpringBoot 项目中的整合使用,以及如何结合 Spring Cache 实现缓存注解化开发,覆盖从 “环境搭建” 到 “实战应用” 的全流程。
Redis简介
数据类型
Redis 支持多种丰富的数据类型,覆盖大部分业务场景:
- String(字符串):最基础类型,用于存储字符串、数字(如用户 token、计数器);
- Hash(哈希):键值对集合,适合存储对象(如用户信息、商品详情);
- List(列表):有序可重复集合,用于消息队列、最新消息列表;
- Set(集合):无序不可重复集合,用于去重、交集 / 并集计算(如共同好友);
- ZSet(有序集合):带分数的 Set,用于排序场景(如排行榜、延迟队列)。
关键优势
- 高性能:基于内存操作,单节点 QPS 可达 10w+;
- 持久化:支持 RDB 快照、AOF 日志两种持久化方式,避免内存数据丢失;
- 分布式友好:支持主从复制、哨兵模式、Cluster 集群,轻松实现高可用与横向扩展;
- 功能丰富:自带发布订阅、Lua 脚本、事务(弱事务)等特性。
Redis基本使用
Windows安装
安装Redis
下载地址:Releases · tporadowski/redis
Redis支持32位和64位。这个需要更具操作系统平台的实际情况决定
- 从Redis 官方仓库下载 Windows 版本安装包(选择最新稳定版);
- 解压到本地目录(如
D:\redis); - 建议将解压目录添加到系统环境变量(方便全局执行命令)。
配置修改
打开解压目录下的redis.windows.conf,修改常用配置:
# 端口(默认6379)
port 6379
# 密码(生产环境必须设置)
requirepass 123456
# 最大内存限制
maxmemory 2gb
启动与连接
- 启动服务端:在解压目录打开 cmd,执行:
redis-server.exe redis.windows.conf
- 启动客户端:新打开 cmd,执行(连接本地服务):
redis-cli.exe -h 127.0.0.1 -p 6379 -a 123456
基本操作示例
以常用数据类型为例:
# String类型:设置/获取值
set username "zhangsan"
get username
# Hash类型:存储用户信息
hset user:1 id 1 name "zhangsan" age 20
hgetall user:1
# List类型:添加/获取列表元素
lpush list:demo "a" "b" "c"
lrange list:demo 0 -1
可视化工具
Another Redis Desktop Manager(ARDM)
- 特点:开源免费、跨平台(Win/Mac/Linux)、支持全数据类型、集群 / 哨兵模式
- 下载:GitHub 仓库
- 安装命令:
# Windows (winget) winget install qishibo.AnotherRedisDesktopManager # Windows (chocolatey) choco install another-redis-desktop-manager
SpringBoot操作Redis
spring-boot-starter-data-redis
启动器核心作用
spring-boot-starter-data-redis 是 SpringBoot 提供的 Redis 快速集成启动器,其核心价值在于 “自动配置 + 依赖聚合”,无需手动导入多个零散依赖,也无需手动编写 Redis 连接配置类,SpringBoot 会自动完成大部分初始化工作,极大简化了 Redis 在 SpringBoot 项目中的集成成本。
启动器核心依赖拆解
该启动器内部默认聚合了以下核心依赖(无需手动引入):
spring-data-redis:Spring Data 家族的核心组件,提供了对 Redis 操作的统一封装(封装了 Redis 客户端的 API,屏蔽了底层客户端的差异),是RedisTemplate、StringRedisTemplate等操作类的核心依赖。lettuce-core:SpringBoot 2.x 及以上版本默认集成的 Redis 客户端(替代了 SpringBoot 1.x 的jedis),基于 Netty 实现,支持异步操作、线程安全、连接池复用,性能更优,适合高并发场景。spring-context-support:提供 Spring 容器对 Redis 的上下文支持,用于整合缓存、序列化等功能。
依赖引入代码(完整)
在 SpringBoot 项目的pom.xml中添加 Redis starter:
<!-- SpringBoot Redis 快速集成启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 可选:若需要手动配置lettuce连接池,引入连接池依赖(启动器已间接依赖,可直接配置) -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
配置 Redis 连接:基础配置 + 进阶优化
基础连接配置(application.yml)
满足本地开发、简单生产环境的基础连接需求,配置项清晰易懂:
spring:
redis:
host: 127.0.0.1 # Redis服务IP地址(生产环境填写服务器内网IP或域名)
port: 6379 # Redis服务端口(默认6379,可自定义修改)
password: 123456 # Redis连接密码(生产环境必须设置,不能为空)
timeout: 5000ms # 连接超时时间(毫秒),超过该时间未连接成功则抛出异常
database: 0 # 连接的Redis数据库索引(Redis默认有16个数据库,索引0-15,默认使用0库)
进阶配置:Lettuce 连接池优化
由于lettuce是线程安全的客户端,通过连接池可以复用连接,减少频繁创建 / 销毁连接的性能损耗,适合高并发场景:
spring:
redis:
host: 127.0.0.1
port: 6379
password: 123456
timeout: 5000ms
database: 0
lettuce: # lettuce 客户端专属配置
pool:
max-active: 8 # 连接池最大活跃连接数(默认8,可根据并发量调整)
max-idle: 8 # 连接池最大空闲连接数(默认8,建议与max-active一致)
min-idle: 2 # 连接池最小空闲连接数(默认0,设置2-4个保底连接,提升响应速度)
max-wait: -1ms # 连接池最大等待时间(-1表示无限制,超过该时间未获取连接则抛出异常)
基本操作
RedisTemplate 与 StringRedisTemplate 详解
两个核心操作类的区别
SpringBoot 默认提供两个 Redis 操作类,核心差异在于序列化方式和适用场景:
| 操作类 | 键序列化方式 | 值序列化方式 | 适用场景 |
|---|---|---|---|
StringRedisTemplate |
StringRedisSerializer |
StringRedisSerializer |
仅操作 String 类型数据(最常用,如缓存 token、简单键值对) |
RedisTemplate<String, Object> |
默认JdkSerializationRedisSerializer |
默认JdkSerializationRedisSerializer |
操作 Object、Hash、List 等复杂数据类型 |
注意:
RedisTemplate默认序列化方式会导致 Redis 中存储的键值出现乱码(以\xAC\xED\x00\x05t\x00\x03开头),因此需要自定义序列化配置
完整操作示例(覆盖多数据类型)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Service
public class RedisDemoService {
// 注入StringRedisTemplate:专用于String类型操作
@Autowired
private StringRedisTemplate stringRedisTemplate;
// 注入RedisTemplate:用于复杂数据类型操作
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// ==================== String 类型操作 ====================
public void operateString(String key, String value) {
// 设置键值对,有效期1小时
stringRedisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);
// 获取键对应的值
String result = stringRedisTemplate.opsForValue().get(key);
// 递增操作(计数器场景:如文章阅读量、点赞数)
stringRedisTemplate.opsForValue().increment("article:read:1001", 1);
// 递减操作
stringRedisTemplate.opsForValue().decrement("article:read:1001", 1);
}
// ==================== Hash 类型操作 ====================
public void operateHash(String userId, User user) {
String hashKey = "user:" + userId;
// 存入单个字段
redisTemplate.opsForHash().put(hashKey, "id", user.getId());
redisTemplate.opsForHash().put(hashKey, "name", user.getName());
// 存入整个对象(字段对应对象属性)
redisTemplate.opsForHash().putAll(hashKey, user);
// 获取单个字段值
String userName = (String) redisTemplate.opsForHash().get(hashKey, "name");
// 获取该Hash的所有字段和值
Map<Object, Object> userMap = redisTemplate.opsForHash().entries(hashKey);
// 获取该Hash的所有字段名
Set<Object> fields = redisTemplate.opsForHash().keys(hashKey);
}
// ==================== List 类型操作(有序可重复) ====================
public void operateList(String listKey) {
// 从列表左侧添加元素(左进右出:队列模式)
redisTemplate.opsForList().leftPush(listKey, "元素1");
redisTemplate.opsForList().leftPushAll(listKey, "元素2", "元素3", "元素4");
// 从列表右侧弹出元素
Object rightPop = redisTemplate.opsForList().rightPop(listKey);
// 从列表右侧添加元素(右进右出:栈模式)
redisTemplate.opsForList().rightPush(listKey, "元素5");
// 获取列表指定区间的元素(0:起始索引,-1:结束索引,表示所有元素)
List<Object> list = redisTemplate.opsForList().range(listKey, 0, -1);
// 获取列表长度
Long size = redisTemplate.opsForList().size(listKey);
}
// ==================== Set 类型操作(无序不可重复) ====================
public void operateSet(String setKey) {
// 添加元素
redisTemplate.opsForSet().add(setKey, "a", "b", "c", "c"); // 重复元素"c"会自动去重
// 获取Set中所有元素
Set<Object> members = redisTemplate.opsForSet().members(setKey);
// 判断元素是否在Set中
Boolean isExist = redisTemplate.opsForSet().isMember(setKey, "a");
// 求两个Set的交集(共同好友场景)
Set<Object> intersect = redisTemplate.opsForSet().intersect("set:1", "set:2");
// 删除指定元素
redisTemplate.opsForSet().remove(setKey, "a");
}
}
工具类封装:完整实用的 RedisUtil
为简化 Redis 操作,避免重复编写模板代码,封装一个支持多数据类型、包含常用操作的RedisUtil工具类,可直接在项目中复用:
package com.yugongyun.admin.utils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Redis工具类
*
* @author ktjy
* @since 2025-09-28
*/
@Component
public class RedisUtil {
@Resource
private RedisTemplate<String, Object> redisTemplate;
// =============================common============================
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
}
}
}
// ============================String=============================
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
*
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key 键
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
// ================================Map=================================
/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
// ============================set=============================
/**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0)
expire(key, time);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
// ===============================list=================================
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}
封装
SpringBoot集成Redis使用Cache缓存
RedisConfig配置
配置核心作用
- 解决
RedisTemplate默认序列化乱码问题(默认使用JdkSerializationRedisSerializer,会导致 Redis 中键值出现二进制乱码,无法直接通过命令行或可视化工具查看); - 配置
CacheManager,将 Spring Cache 的缓存介质指定为 Redis,同时设置缓存默认过期时间、序列化方式等。@Configuration public class RedisConfig { @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); // 解决查询缓存转换异常的问题 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 注册JavaTimeModule以支持LocalDateTime等Java 8时间类型 om.registerModule(new JavaTimeModule()); om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(om, Object.class); // 2. 设置 value 的序列化规则和 key 的序列化规则 template.setValueSerializer(new StringRedisSerializer()); // 修改:对值使用StringRedisSerializer template.setKeySerializer(new StringRedisSerializer()); template.afterPropertiesSet(); return template; } /** * 配置缓存管理器(支持 @Cacheable/@CachePut/@CacheEvict 等注解) * @param redisConnectionFactory Redis 连接工厂 * @return 缓存管理器 */ @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { // 1. 复用序列化配置 RedisSerializer<String> stringSerializer = new StringRedisSerializer(); //解决缓存转换异常问题 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 注册JavaTimeModule以支持LocalDateTime等Java 8时间类型 om.registerModule(new JavaTimeModule()); om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(om, Object.class); // 配置序列化解决乱码问题 RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(7)) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringSerializer)). serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) .disableCachingNullValues(); // 3. 构建缓存管理器 return RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(cacheConfig).build(); } }
Cache注解
Spring Cache 提供了多个注解实现缓存管理,核心 3 个注解的详细说明如下:
| 注解名 | 核心作用 | 常用属性及说明 |
|---|---|---|
@Cacheable |
查询缓存:先查缓存,无缓存则执行方法并写入缓存 | 1. value:缓存名称(必填,用于区分不同缓存组,如 "user")2. key:缓存键(支持 SpEL 表达式,如 "#userId")3. condition:缓存条件(满足条件才缓存,如 "#userId > 0")4. unless:排除条件(满足条件不缓存,如 "#result == null") |
@CachePut |
更新缓存:执行方法后,将结果写入缓存(不查缓存) | 1. value:缓存名称(与 @Cacheable 一致)2. key:缓存键(与 @Cacheable 一致,保证更新同一个缓存) |
@CacheEvict |
删除缓存:删除指定缓存或缓存组 | 1. value:缓存名称2. key:缓存键(指定删除某个缓存)3. allEntries:是否删除该缓存组所有缓存(默认 false,如allEntries = true) |
测试使用
- 在UserService中编写测试方法(没有这个类的自行创建一个业务类调用数据层的方法)添加一个getUser的方法:
@Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { @Autowired private UserMapper userMapper; @Cacheable(value = "user",keyGenerator = "keyGenerator") public User getUser(Long id){ return userMapper.selectById(id); } } - 编写测试方法:
@Test public void testCache(){ User user = userService.getUser(2L); System.out.println(user.getUsrName()); } - 执行测试方法:
- 第一次执行我们可以从sql日志中看出有执行过sql语句:

- 第二次执行因为走的是缓存所以并没有执行sql:

- 第一次执行我们可以从sql日志中看出有执行过sql语句:
总结
本文从 Redis 基础(数据类型、安装使用),到 SpringBoot 的原生整合,再到结合 Spring Cache 实现注解化缓存,覆盖了 Redis 在 Java 后端开发中的核心使用场景。掌握这些内容后,即可在项目中快速落地 Redis 缓存,提升系统性能。
更多推荐




所有评论(0)