无忧网站优化,免费国外网站模板,千锋前端培训班,婴儿辅食中企动力提供网站建设相信在项目中#xff0c;你一定是经常使用 Redis #xff0c;那么#xff0c;你是怎么使用的呢#xff1f;在使用时#xff0c;有没有遇到同我一样#xff0c;对象缓存序列化问题的呢#xff1f;那么#xff0c;你又是如何解决的呢#xff1f;
Redis 使用示例
添加依…相信在项目中你一定是经常使用 Redis 那么你是怎么使用的呢在使用时有没有遇到同我一样对象缓存序列化问题的呢那么你又是如何解决的呢
Redis 使用示例
添加依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency在应用启动如何添加启用缓存注解EnableCaching。
假如我们有一个用户对象UserVo
Data
public class UserVo implements Serializable {Serialprivate static final long serialVersionUID 2215423070276994378L;private Long id;private String name;private LocalDateTime createDateTime;}这里我们实现了 Serializable 接口。
在我们需要缓存的方法上使用 Cacheable 注解就表示如果返回的对象不是 null 时就会对其进行缓存下次查询首先会去缓存中查询查到了就直接返回不会再去数据库查询查不到再去数据库查询。
Service
Slf4j
public class UserServiceImpl implements IUserService {OverrideCacheable(value sample-redis,key user-#id,unless #result null)public UserVo getUserById(Long id) {log.info(userVo from db query);UserVo userVo new UserVo();userVo.setId(1L);userVo.setName(Zhang San);userVo.setCreateDateTime(LocalDateTime.now());return userVo;}}核心代码
Cacheable(value sample-redis,key user-#id,unless #result null
)模拟测试再写一个测试接口
RestController
RequestMapping(/sample)
RequiredArgsConstructor
Slf4j
public class SampleController {private final IUserService userService;GetMapping(/user/{id})public UserVo getUserById(PathVariable Long id) {UserVo vo userService.getUserById(id);log.info(vo: {}, JacksonUtils.json(vo));return vo;}}我们再加上连接 redis 的配置
spring:data:redis:host: localhostport: 6379测试
### getUserById
GET http://localhost:8080/sample/user/1输出结果跟我们想的一样第一次从数据库查后面都从缓存直接返回。
总结一下 添加 spring-boot-starter-data-redis 依赖。 使用启用缓存注解EnableCaching。 需要缓存的对象实现 Serializable 接口。 使用 Cacheable 注解缓存查询的结果。
遇到问题
在上面我们通过 spring boot 提供的 redis 实现了查询对象缓存这样一个功能有下面几个问题
缓存的对象必须序列化不然会报错。redis 存储的数据看不懂可以转成 json 格式吗使用 Jackson 时遇到特殊类型的字段会报错比如 LocalDateTime。
第1个问题如果对象没有实现 Serializable 接口会报错 关键信息
java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [xxx.xxx.UserVo]我详细描述一下第3个问题默认是使用 Jdk序列化 JdkSerializationRedisSerializerredis 里面存的数据如下 问题很明显对象必须要实现序列化接口存的数据不易查看所以改用 GenericJackson2JsonRedisSerializer 这就有了第3个问题。
我们加上下面的配置就能解决第2个问题。
Bean
public RedisCacheConfiguration redisCacheConfiguration() {return RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
}下面看第三个问题的错误 如何解决
既然有了明确的错误提示那也是好解决的我们可以这样
JsonDeserialize(using LocalDateTimeDeserializer.class) // 反序列化
JsonSerialize(using LocalDateTimeSerializer.class) // 序列化
private LocalDateTime createDateTime;这样就可以了我们看下redis里面存的数据
{class:com.fengwenyi.erwin.component.sample.redis.vo.UserVo,id:1,name:Zhang San,createDateTime:[2023,12,29,23,44,3,479011000]}其实到这里已经解决了问题那有没有更省心的办法呢
解决办法
其实我们知道使用的就是 Jackson 进行 json 转换而 json 转换遇到 LocalDateTime 问题时我们配置一下 module 就可以了因为默认用的 SimpleModule我们改用 JavaTimeModule 就可以了。
这时候问题又来啦错误如下 这时候存的数据如下
{id:1,name:Zhang San,createDateTime:2023-12-29T23:31:52.548517}这就涉及到 Jackson 序列化漏洞的问题了采用了白名单机制我们就粗暴一点
jsonMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL
);redis 存的数据如下
[com.fengwenyi.erwin.component.sample.redis.vo.UserVo,{id:1,name:Zhang San,createDateTime:2023-12-29T23:56:18.197203}]最后来一段完整的 RedisCacheConfiguration 配置代码
Bean
public RedisCacheConfiguration redisCacheConfiguration() {return RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(RedisSerializationContext.SerializationPair
// .fromSerializer(RedisSerializer.json())
// .fromSerializer(
// new GenericJackson2JsonRedisSerializer()
// ).fromSerializer(redisSerializer()));
}private RedisSerializerObject redisSerializer() {JsonMapper jsonMapper new JsonMapper();JacksonUtils.configure(jsonMapper);jsonMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);return new GenericJackson2JsonRedisSerializer(jsonMapper);
}希望今天的分享对你有一定的帮助。