多级缓存之一:Redis集中式缓存应用
2019-07-15 本文已影响0人
YoSaukit
接上一篇分布式会话实现(Springboot+redis),完成了用户登录验证成功后将对应的登录信息和登录凭证保存到redis。
本篇以保存商品详情页信息为例,完成redis商品详情的存取的应用。
缓存的数据库中间件,相当于nosql数据库,只能用key-value查询。
集中式的管理缓存
○ 单机版
单个业务结点的redis挂了业务会受影响
○ sentinal哨兵模式
用redis sentinal来管理(心跳机制)redis master和redis slave,应用程序只需要感知redis sentinal
○ 集群cluster模式
以上三种模式都被spring-data-redis和jedis jar支撑,客户端只需要做配置即可启用。
三种设计模式的性能瓶颈都是在水平拓展后的容量问题上,整个设计思路实际上不变。
1. 未序列化使用redis
key保存item_id,value保存itemModel
ItemController.java
```
...
//根据商品的id到redis内获取
ItemModel itemModel = (ItemModel) redisTemplate.opsForValue().get("item_"+id);
//若redis内不存在对应的itemModel,则访问下游service
if (itemModel == null){
itemModel = itemService.getItemById(id);
//设置itemModel到redis内
redisTemplate.opsForValue().set("item_"+id,itemModel);
redisTemplate.expire("item_"+id,10, TimeUnit.MINUTES);
}
...
```
Service层,DAO层操作省略,简单的查询操作。
此时访问/item/get?id=2,查看redis
未序列化使用
2. 序列化key和value
itemModel中有joda.time类型字段,因此采用json序列化和反序列化方式对时间字段进行处理
-
RedisConfig.java
@Component @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600) public class RedisConfig { @Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){ RedisTemplate redisTemplate = new RedisTemplate(); redisTemplate.setConnectionFactory(redisConnectionFactory); //首先解决key序列化方式 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(stringRedisSerializer); //解决value序列化方式 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); SimpleModule simpleModule = new SimpleModule(); simpleModule.addSerializer(DateTime.class, new JodaDateTimeJsonSerializer()); simpleModule.addDeserializer(DateTime.class, new JodaDateTimeJsonDeSerializer()); objectMapper.registerModule(simpleModule); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); return redisTemplate; }
}
```
-
JodaDateTimeJsonSerializer.java
public class JodaDateTimeJsonSerializer extends JsonSerializer<DateTime> {
@Override
public void serialize(DateTime dateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(dateTime.toString("yyyy-MM-dd HH:mm:ss"));
}
}
-
JodaDateTimeJsonDeSerializer.java
public class JodaDateTimeJsonDeSerializer extends JsonDeserializer<DateTime> {
@Override
public DateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
String dateString = jsonParser.readValueAs(String.class);
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
return DateTime.parse(dateString,formatter);
}
}
先清理掉redis中的数据(flushall命令),再次访问/item/get?id=2,查看redis
序列化使用redis
此时能够看到序列化后的key和value值,但存在一个问题,第一次访问后,数据能保存到redis中,但是再次访问时(访问redis内数据)会报错
请求redis内数据报错
查看console显示
Resolved [java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.miaoshaproject.service.model.ItemModel]
这是因为前面redis保存的value信息只是一个json字符串,没有指定包含的类的信息,因此必须在jackson对应的序列化方式中,没有包含类的信息需要在转化方法中强制指定类的信息。
因此需要在RedisConfig中加入
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
此时查看redis
加入类信息
此时,value中标识了如何解析这些参数的信息。至此,redis的简单应用结束。