java每日精进 5.25【Redis缓存】
1.Redis 缓存实现
1.1 编程式缓存(Spring Data Redis)
编程式缓存使用 Spring Data Redis 框架,通过 RedisTemplate 操作 Redis,结合 Redisson 客户端实现。本例以缓存 OAuth2 访问令牌(OAuth2AccessTokenDO)为例。
步骤 1:添加依赖
项目引入了 Redisson 的 Spring Boot Starter 依赖,以支持 Redis 操作。
<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId>
</dependency>
- 解释:Redisson 是一个功能强大的 Redis 客户端,支持分布式锁、队列、限流等功能。引入此依赖后,Spring Boot 可以通过 Redisson 连接 Redis,并使用 RedisTemplate 进行编程式缓存操作。
步骤 2:配置 Redis 连接
在 application-local.yaml 文件中,通过 spring.redis 配置项设置 Redis 连接参数。
redis:host: 127.0.0.1 # Redis 服务器地址port: 6379 # Redis 端口database: 0 # Redis 数据库索引
# password: dev # 密码(生产环境建议启用)
- 解释:此配置指定了 Redis 服务器的地址、端口和数据库索引。yudao 项目指出 Redisson 的默认配置通常无需额外调优,适用于大多数场景。
步骤 3:配置 RedisTemplate(JSON 序列化)
在 YudaoRedisAutoConfiguration 类中,项目自定义了 RedisTemplate,使用 JSON 序列化存储复杂对象的值。
@AutoConfiguration(before = RedissonAutoConfiguration.class)
public class YudaoRedisAutoConfiguration {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {// 创建 RedisTemplateRedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);// 设置键序列化(String)template.setKeySerializer(RedisSerializer.string());template.setHashKeySerializer(RedisSerializer.string());// 设置值序列化(JSON)template.setValueSerializer(buildRedisSerializer());template.setHashValueSerializer(buildRedisSerializer());return template;}public static RedisSerializer<?> buildRedisSerializer() {RedisSerializer<Object> json = RedisSerializer.json();// 支持 LocalDateTime 序列化ObjectMapper objectMapper = (ObjectMapper) ReflectUtil.getFieldValue(json, "mapper");objectMapper.registerModules(new JavaTimeModule());return json;}
}
解释:
- 目的:定义一个 RedisTemplate bean,用于 Redis 的键值操作。
- 序列化:
- 键:使用 StringRedisSerializer,确保键以字符串形式存储(如 oauth2_access_token:token123)。
- 值:使用 Jackson2JsonRedisSerializer(通过 RedisSerializer.json()),将复杂对象(如 OAuth2AccessTokenDO)序列化为 JSON。
- LocalDateTime 支持:通过注册 JavaTimeModule,确保 Jackson 可以正确序列化/反序列化 Java 8 的日期时间类型(如 LocalDateTime)。
- 优先级:@AutoConfiguration(before = RedissonAutoConfiguration.class) 确保自定义 RedisTemplate 在 Redisson 默认配置之前加载,以覆盖默认设置。
步骤 4:定义数据对象(OAuth2AccessTokenDO)
项目定义了一个数据对象 OAuth2AccessTokenDO,用于表示存储在 Redis 中的访问令牌结构。
@TableName(value = "system_oauth2_access_token", autoResultMap = true)
@KeySequence("system_oauth2_access_token_seq")
@Data
@EqualsAndHashCode(callSuper = true)
public class OAuth2AccessTokenDO extends TenantBaseDO {@TableIdprivate Long id; // 主键private String accessToken; // 访问令牌private String refreshToken; // 刷新令牌private Long userId; // 用户编号private Integer userType; // 用户类型@TableField(typeHandler = JacksonTypeHandler.class)private Map<String, String> userInfo; // 用户信息private String clientId; // 客户端编号@TableField(typeHandler = JacksonTypeHandler.class)private List<String> scopes; // 授权范围private LocalDateTime expiresTime; // 过期时间
}
解释:
- 作用:OAuth2AccessTokenDO 是一个数据对象(DO),用于映射数据库表 system_oauth2_access_token 和 Redis 中的缓存数据。
- 注解:
- @TableName:指定 MyBatis-Plus 映射的表名。
- @KeySequence:支持 Oracle、PostgreSQL 等数据库的主键自增(MySQL 可忽略)。
- @TableField(typeHandler = JacksonTypeHandler.class):对复杂字段(如 userInfo 和 scopes)使用 Jackson 序列化,存储为 JSON。
- 字段:包含访问令牌、用户编号、过期时间等信息,适合缓存复杂对象。
步骤 5:定义 Redis Key 常量(RedisKeyConstants)
项目通过 RedisKeyConstants 类集中管理 Redis 键,避免键名散落在代码中。
public interface RedisKeyConstants {String OAUTH2_ACCESS_TOKEN = "oauth2_access_token:%s";// 其他键定义...
}
解释:
- 目的:统一管理 Redis 键的格式,类似数据库表的规范管理。
- 键格式:OAUTH2_ACCESS_TOKEN 使用 %s 占位符,动态生成键(如 oauth2_access_token:token123)。
- 优势:通过查看 RedisKeyConstants,可以快速了解模块使用的所有 Redis 键,便于维护和调试。
步骤 6:实现 Redis 数据访问对象(OAuth2AccessTokenRedisDAO)
OAuth2AccessTokenRedisDAO 类封装了对 OAuth2AccessTokenDO 的 Redis 缓存操作。
@Repository
public class OAuth2AccessTokenRedisDAO {@Resourceprivate StringRedisTemplate stringRedisTemplate;public OAuth2AccessTokenDO get(String accessToken) {String redisKey = formatKey(accessToken);return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), OAuth2AccessTokenDO.class);}public void set(OAuth2AccessTokenDO accessTokenDO) {String redisKey = formatKey(accessTokenDO.getAccessToken());// 清理多余字段,避免缓存accessTokenDO.setUpdater(null).setUpdateTime(null).setCreateTime(null).setCreator(null).setDeleted(null);long time = LocalDateTimeUtil.between(LocalDateTime.now(), accessTokenDO.getExpiresTime(), ChronoUnit.SECONDS);if (time > 0) {stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(accessTokenDO), time, TimeUnit.SECONDS);}}public void delete(String accessToken) {String redisKey = formatKey(accessToken);stringRedisTemplate.delete(redisKey);}public void deleteList(Collection<String> accessTokens) {List<String> redisKeys = CollectionUtils.convertList(accessTokens, OAuth2AccessTokenRedisDAO::formatKey);stringRedisTemplate.delete(redisKeys);}private static String formatKey(String accessToken) {return String.format(OAUTH2_ACCESS_TOKEN, accessToken);}
}
解释:
- 注入:@Resource private StringRedisTemplate stringRedisTemplate 注入 StringRedisTemplate,用于操作字符串类型的键值对(值仍为 JSON)。
- 方法:
- get:从 Redis 获取指定访问令牌的 OAuth2AccessTokenDO,通过 JsonUtils.parseObject 反序列化 JSON 为对象。
- set:将 OAuth2AccessTokenDO 序列化为 JSON 存储到 Redis,设置动态过期时间(基于 expiresTime)。清理多余字段(如 updater)以减少缓存体积。
- delete 和 deleteList:删除单个或多个访问令牌的缓存。
- 键生成:formatKey 使用 RedisKeyConstants.OAUTH2_ACCESS_TOKEN 格式化键名,确保一致性。
步骤 7:业务逻辑中使用 Redis 缓存
在 OAuth2TokenServiceImpl 中,通过注入 OAuth2AccessTokenRedisDAO,实现访问令牌的缓存操作。
@Service
public class OAuth2TokenServiceImpl {@Resourceprivate OAuth2AccessTokenRedisDAO accessTokenRedisDAO;// 示例方法:获取访问令牌public OAuth2AccessTokenDO getAccessToken(String accessToken) {// 先从 Redis 获取OAuth2AccessTokenDO tokenDO = accessTokenRedisDAO.get(accessToken);if (tokenDO != null) {return tokenDO;}// 如果 Redis 没有,从数据库查询tokenDO = accessTokenMapper.selectByAccessToken(accessToken);if (tokenDO != null) {// 存入 RedisaccessTokenRedisDAO.set(tokenDO);}return tokenDO;}
}
解释:
- 缓存优先:先尝试从 Redis 获取令牌,若存在则直接返回。
- 数据库回查:若 Redis 缓存不存在,则从数据库查询,并将结果存入 Redis。
- 封装性:OAuth2AccessTokenRedisDAO 屏蔽了底层的 Redis 操作,业务代码只需调用 DAO 方法,逻辑简洁。
1.2 声明式缓存(Spring Cache)
声明式缓存基于 Spring Cache 框架,使用注解(如 @Cacheable)简化缓存操作。本例以角色(RoleDO)缓存为例。
步骤 1:添加依赖
引入 Spring Cache 依赖以启用注解式缓存。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>
- 解释:此依赖启用 Spring Cache 功能,支持 @Cacheable、@CachePut 和 @CacheEvict 注解。
步骤 2:配置 Redis 作为缓存后端
在 application.yaml 中配置 Redis 连接(与编程式缓存相同),并在 YudaoCacheAutoConfiguration 类中配置 Spring Cache。
@AutoConfiguration
@EnableConfigurationProperties({CacheProperties.class, YudaoCacheProperties.class})
@EnableCaching
public class YudaoCacheAutoConfiguration {@Bean@Primarypublic RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();// 使用单冒号作为键前缀分隔符config = config.computePrefixWith(cacheName -> {String keyPrefix = cacheProperties.getRedis().getKeyPrefix();if (StringUtils.hasText(keyPrefix)) {keyPrefix = keyPrefix.endsWith(":") ? keyPrefix : keyPrefix + ":";return keyPrefix + cacheName + ":";}return cacheName + ":";});// 使用 JSON 序列化config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(YudaoRedisAutoConfiguration.buildRedisSerializer()));// 设置缓存属性CacheProperties.Redis redisProperties = cacheProperties.getRedis();if (redisProperties.getTimeToLive() != null) {config = config.entryTtl(redisProperties.getTimeToLive());}if (!redisProperties.isCacheNullValues()) {config = config.disableCachingNullValues();}if (!redisProperties.isUseKeyPrefix()) {config = config.disableKeyPrefix();}return config;}@Beanpublic RedisCacheManager redisCacheManager(RedisTemplate<String, Object> redisTemplate,RedisCacheConfiguration redisCacheConfiguration,YudaoCacheProperties yudaoCacheProperties) {RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory());RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory,BatchStrategies.scan(yudaoCacheProperties.getRedisScanBatchSize()));return new TimeoutRedisCacheManager(cacheWriter, redisCacheConfiguration);}
}
解释:
- 启用缓存:@EnableCaching 激活 Spring Cache 功能。
- 键前缀:自定义键前缀格式(如 cacheName:),使用单冒号分隔,避免工具(如 Redis Desktop Manager)显示问题。
- 序列化:复用 YudaoRedisAutoConfiguration.buildRedisSerializer(),确保值以 JSON 格式存储。
- 缓存属性:
- timeToLive:设置默认缓存过期时间(项目默认 1 小时)。
- disableCachingNullValues:禁止缓存 null 值。
- disableKeyPrefix:可选禁用键前缀。
- RedisCacheManager:创建缓存管理器,基于 Redis 实现缓存存储。
-
步骤 3:使用 Spring Cache 注解
在 RoleServiceImpl 中,使用 @Cacheable 和 @CacheEvict 实现角色缓存。
@Service
public class RoleServiceImpl {@Resourceprivate RoleMapper roleMapper;@Cacheable(value = RedisKeyConstants.ROLE, key = "#id", unless = "#result == null")public RoleDO getRoleFromCache(Long id) {return roleMapper.selectById(id);}@Transactional(rollbackFor = Exception.class)@CacheEvict(value = RedisKeyConstants.ROLE, key = "#id")public void deleteRole(Long id) {RoleDO role = validateRoleForUpdate(id);roleMapper.deleteById(id);permissionService.processRoleDeleted(id);LogRecordContext.putVariable("role", role);}
}
- 解释:
- @Cacheable:
- value = RedisKeyConstants.ROLE:指定缓存名称(对应 Redis 键前缀,如 role:)。
- key = "#id":使用方法参数 id 作为缓存键(如 role:123)。
- unless = "#result == null":避免缓存 null 值。
- 执行逻辑:先检查 Redis 是否有缓存,若有则返回;否则执行方法并缓存结果。
- @CacheEvict:在删除角色时,移除对应的缓存键(如 role:123),确保缓存与数据库一致。
- 被动读策略:仅在查询时缓存数据(getRoleFromCache),更新或删除时清除缓存(deleteRole),避免缓存非必要数据。
- @Cacheable:
步骤 4:缓存与数据库一致性
yudao 项目采用被动读策略:
- 查询:从 Redis 获取数据,若无则从 MySQL 查询并缓存。
- 更新/删除:更新 MySQL 后,删除 Redis 缓存,确保下次查询时重新从数据库加载。
- 原因:
- 保证 Redis 和 MySQL 数据一致性。
- 避免主动写入非必要数据,节省 Redis 存储空间。
2.在新项目中实现 Redis 缓存
2.1 项目结构
new-project/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/demo/
│ │ │ ├── config/
│ │ │ │ └── RedisConfig.java
│ │ │ ├── dao/
│ │ │ │ └── UserRedisDAO.java
│ │ │ ├── entity/
│ │ │ │ └── UserDO.java
│ │ │ ├── service/
│ │ │ │ ├── UserService.java
│ │ │ │ └── UserServiceImpl.java
│ │ │ └── constants/
│ │ │ └── RedisKeyConstants.java
│ │ └── resources/
│ │ └── application.yml
│ └── pom.xml
2.2 依赖配置
在 pom.xml 中添加必要的依赖。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>demo</artifactId><version>0.0.1-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.5</version><relativePath/></parent><dependencies><!-- Spring Boot Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Redis 依赖 --><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.25.0</version></dependency><!-- Spring Cache 依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><!-- MyBatis-Plus 依赖 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3</version></dependency><!-- MySQL 依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><!-- Lombok 依赖 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency><!-- Hutool 工具库 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.20</version></dependency></dependencies>
</project>
解释:
- spring-boot-starter-web:提供 Web 功能。
- redisson-spring-boot-starter:支持 Redis 操作。
- spring-boot-starter-cache:支持 Spring Cache 注解。
- mybatis-plus-boot-starter:用于数据库操作。
- mysql-connector-java:MySQL 数据库驱动。
- lombok:简化代码。
- hutool-all:提供 JSON 序列化等工具,模拟 yudao 的 JsonUtils。
2.3 配置 Redis 连接
在 application.yml 中配置 Redis 和数据库连接。
spring:redis:host: 127.0.0.1port: 6379database: 0datasource:url: jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: rootcache:redis:time-to-live: 3600000 # 缓存默认过期时间 1 小时(毫秒)key-prefix: "cache:" # 缓存键前缀cache-null-values: false # 不缓存 null 值
mybatis-plus:mapper-locations: classpath*:/mapper/*.xml
解释:
- Redis 配置:与 yudao 一致,指定本地 Redis 服务器。
- Cache 配置:设置默认过期时间为 1 小时,使用 cache: 前缀。
- MySQL 配置:连接本地 MySQL 数据库(需创建 demo 数据库)。
- MyBatis-Plus:配置 Mapper XML 文件路径。
2.4 配置 RedisTemplate 和 Spring Cache
创建 RedisConfig 类,配置 RedisTemplate 和 Spring Cache。
package com.example.demo.config;import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.time.Duration;@AutoConfiguration
@EnableCaching
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);template.setKeySerializer(new StringRedisSerializer());template.setHashKeySerializer(new StringRedisSerializer());template.setValueSerializer(jsonSerializer());template.setHashValueSerializer(jsonSerializer());return template;}private RedisSerializer<Object> jsonSerializer() {RedisSerializer<Object> json = RedisSerializer.json();ObjectMapper mapper = (ObjectMapper) ReflectUtil.getFieldValue(json, "mapper");mapper.registerModule(new JavaTimeModule());return json;}@Bean@Primarypublic RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();config = config.computePrefixWith(cacheName -> cacheProperties.getRedis().getKeyPrefix() + cacheName + ":");config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonSerializer()));CacheProperties.Redis redisProperties = cacheProperties.getRedis();if (redisProperties.getTimeToLive() != null) {config = config.entryTtl(redisProperties.getTimeToLive());}if (!redisProperties.isCacheNullValues()) {config = config.disableCachingNullValues();}return config;}@Beanpublic RedisCacheManager redisCacheManager(RedisTemplate<String, Object> redisTemplate,RedisCacheConfiguration redisCacheConfiguration) {RedisConnectionFactory factory = redisTemplate.getConnectionFactory();RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(factory);return new RedisCacheManager(cacheWriter, redisCacheConfiguration);}
}
- 解释:
- RedisTemplate:与 yudao 一致,使用字符串序列化键,JSON 序列化值,支持 LocalDateTime。
- Spring Cache:启用 @EnableCaching,配置 RedisCacheConfiguration 使用 JSON 序列化和自定义键前缀。
- RedisCacheManager:创建缓存管理器,基于 Redis 存储缓存。
注意:ReflectUtil 模拟 yudao 的反射操作,需替换为 Hutool 的 ReflectUtil 或直接修改 ObjectMapper:
import cn.hutool.core.util.ReflectUtil;
2.5 定义数据对象(UserDO)
创建 UserDO 类,表示用户信息。
package com.example.demo.entity;import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.time.LocalDateTime;@TableName("user")
@Data
public class UserDO {@TableIdprivate Long id;private String username;private String email;private LocalDateTime createTime;
}
解释:UserDO 映射数据库表 user,包含基本用户信息。需在 MySQL 中创建表:
CREATE TABLE user (id BIGINT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50) NOT NULL,email VARCHAR(100),create_time DATETIME
);
2.6 定义 Redis 键常量
创建 RedisKeyConstants 类,定义 Redis 键。
package com.example.demo.constants;public interface RedisKeyConstants {String USER = "user:%s";
}
解释:定义用户缓存的键格式,如 user:123。
2.7 实现 Redis 数据访问对象(UserRedisDAO)
创建 UserRedisDAO 类,封装用户缓存操作。
package com.example.demo.dao;import cn.hutool.json.JSONUtil;
import com.example.demo.constants.RedisKeyConstants;
import com.example.demo.entity.UserDO;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;@Repository
public class UserRedisDAO {@Resourceprivate StringRedisTemplate stringRedisTemplate;public UserDO get(Long id) {String redisKey = formatKey(id);String value = stringRedisTemplate.opsForValue().get(redisKey);return JSONUtil.toBean(value, UserDO.class);}public void set(UserDO userDO) {String redisKey = formatKey(userDO.getId());userDO.setCreateTime(null); // 清理多余字段stringRedisTemplate.opsForValue().set(redisKey, JSONUtil.toJsonStr(userDO), 3600, TimeUnit.SECONDS);}public void delete(Long id) {String redisKey = formatKey(id);stringRedisTemplate.delete(redisKey);}private static String formatKey(Long id) {return String.format(RedisKeyConstants.USER, id);}
}
解释:
- 注入:使用 StringRedisTemplate 操作 JSON 字符串。
- 方法:
- get:从 Redis 获取用户数据,反序列化为 UserDO。
- set:将 UserDO 序列化为 JSON,设置 1 小时过期时间。
- delete:删除指定用户的缓存。
- JSON 处理:使用 Hutool 的 JSONUtil 替代 yudao 的 JsonUtils。
2.8 实现业务逻辑
创建 UserService 接口和 UserServiceImpl 实现类,支持编程式和声明式缓存。
package com.example.demo.service;import com.example.demo.entity.UserDO;public interface UserService {UserDO getUser(Long id); // 编程式缓存UserDO getUserFromCache(Long id); // 声明式缓存void deleteUser(Long id);
}
package com.example.demo.service;import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.demo.constants.RedisKeyConstants;
import com.example.demo.dao.UserRedisDAO;
import com.example.demo.entity.UserDO;
import com.example.demo.mapper.UserMapper;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;import javax.annotation.Resource;@Service
public class UserServiceImpl implements UserService {@Resourceprivate UserMapper userMapper;@Resourceprivate UserRedisDAO userRedisDAO;@Overridepublic UserDO getUser(Long id) {UserDO user = userRedisDAO.get(id);if (user != null) {return user;}user = userMapper.selectById(id);if (user != null) {userRedisDAO.set(user);}return user;}@Override@Cacheable(value = RedisKeyConstants.USER, key = "#id", unless = "#result == null")public UserDO getUserFromCache(Long id) {return userMapper.selectById(id);}@Override@CacheEvict(value = RedisKeyConstants.USER, key = "#id")public void deleteUser(Long id) {userMapper.deleteById(id);// 缓存通过 @CacheEvict 自动清除}
}
- 解释:
- 编程式缓存(getUser):先查 Redis,若无则查数据库并缓存。
- 声明式缓存(getUserFromCache):使用 @Cacheable,自动处理缓存逻辑。
- 删除(deleteUser):删除数据库记录并通过 @CacheEvict 清除缓存。