2 Springboot中使用redis,配置redis的key value生成策略
上一篇里讲过了redis在spring boot中的简单使用,对于单个对象的增删改查的默认操作。
下面来看一下在redis中,这些缓存的数据是如何存储的,为了便于后面的缓存的key的可读性,先修改一下cache的key。
@CacheConfig(cacheNames = "post")
public interface PostRepository extends PagingAndSortingRepository<Post, Integer> {
@Cacheable(key = "'PostId' + #p0")
Post findById(int id);
/**
* 新增或修改时
*/
@CachePut(key = "'PostId' + #p0.id")
@Override
Post save(Post post);
@Transactional
@Modifying
@CacheEvict(key = "'PostId' + #p0")
int deleteById(int id);
}
给key上加个字符串postId,用类似于postId3作为key,整个Post对象作为value。调用controller的save接口添加一条Post数据,打开redis可视化管理器,查看一下保存的这条数据:
发现key是以post:XX开头的乱码形式。这是默认的key生成策略,是通过序列化Serializable后生成的key,当读取缓存时系统再通过反序列化得到Post对象。
如果我们想修改序列化方式,来生成一个可读的key和value,下面是方法。
譬如如果key我想用字符串如 PostId1,value为Post对象转成的Json对象:
package com.tianyalei.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Created by wuwf on 17/4/24.
*/
@Configuration
public class RedisCacheConfig {
@Bean
public CacheManager cacheManager(RedisTemplate<?,?> redisTemplate) {
CacheManager cacheManager = new RedisCacheManager(redisTemplate);
return cacheManager;
}
@Bean
public RedisTemplate<String, String> getRedisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
//key序列化方式,但是如果方法上有Long等非String类型的话,会报类型转换错误
//所以在没有自己定义key生成策略的时候,以下这个代码建议不要这么写,可以不配置或者自己实现ObjectRedisSerializer
RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型不可以会出现异常信息;
redisTemplate.setKeySerializer(redisSerializer);
// redisTemplate.setHashKeySerializer(redisSerializer);
// redisTemplate.setValueSerializer(redisSerializer);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
上面这个类主要是定制RedisTemplate的KeySerializer和ValueSerializer。其中StringRedisSerializer和Jackson2JsonRedisSerializer都是系统提供的已实现的序列化方式。
StringXX是转为String,JacksonXX是将对象转为json。需要注意这里Key使用了StringRedisSerializer,那么Key只能是String类型的,不能为Long,Integer,否则会报错抛异常。就是假如PostRepository里定义的@Cacheable(key="#p0")的话就会报错,因为这样作为key的是int型,key必须为String。
上面的方法就是设置了key和value的序列化方式,然后返回默认的RedisTemplate。RedisTemplate有几个默认的实现类,常用的如StringRedisTemplate就是提供的RedisTemplate<String, String>的实现。可以参考下面的文章简单了解下StringRedisTemplate。
http://blog.didispace.com/springbootredis/和http://blog.csdn.net/fengzheku/article/details/49735785
StringRedisTemplate其实就是使用StringRedisSerializer对key,value设置序列化。
当然也可以自己定义序列化方式,使用别的Json工具类,或者别的什么方法来完成序列化方式。 完成RedisTemplate的设置后,再次save一个Post对象来看看在redis里的存储方式。
可以看到PostId12就是刚添加成功对象,key为PostId12,即是PostResposity里配置的key,value为Json字符串和一个类名。
然后还多了一个post~keys的zset对象,里面存放的是key。
通过上面的配置,我们就完成对序列化方式自定义的配置,尤其是key的定制,能方便日后的查看以及在别的地方操作key时更易识别。
在上一篇里,还提到了无需配置yml中redis的属性,ip、port之类的,系统会识别默认的。下面来看看如何使用自己的redis配置。
修改yml文件:
spring:
jpa:
database: mysql
show-sql: true
hibernate:
ddl-auto: update
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/tx2
username: root
password:
redis:
host: localhost
port: 6379
password:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: 10000
这里面加入了redis 的配置。可以用ctrl加左键点击host或者post属性,进入类。
这个就是采用prefix=spring.redis前缀的配置类,我们也可以自定义类似的配置类。
在配置文件里设置了ip和port及pool等属性,然后打开RedisCacheConfig类,来使用yml里的这些redis配置。
package com.tianyalei.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
/**
* Created by wuwf on 17/4/24.
*/
@Configuration
public class RedisCacheConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.pool.max-active}")
private int maxActive;
@Value("${spring.redis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.pool.min-idle}")
private int minIdle;
@Value("${spring.redis.pool.max-wait}")
private int maxWait;
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setPassword(password);
factory.setHostName(host);
factory.setPort(port);
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxActive);
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
jedisPoolConfig.setMaxWaitMillis(maxWait);
factory.setPoolConfig(jedisPoolConfig);
return factory;
}
@Bean
public RedisTemplate<String, String> getRedisTemplate() {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
//key序列化方式,但是如果方法上有Long等非String类型的话,会报类型转换错误
RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型不可以会出现异常信息;
redisTemplate.setKeySerializer(redisSerializer);
// redisTemplate.setHashKeySerializer(redisSerializer);
// redisTemplate.setValueSerializer(redisSerializer);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
配置文件里的内容主要目的就是为了配置JedisConnectionFactory,这里我们使用配置文件定义的属性来创建一个自己的JedisConnectionFactory。然后在创建RedisTemplate时使用这个自定义的JedisConnectionFactory即可。
这样就完成了redis的自定义信息,以后就可以使用RedisTemplate来操作redis了。可以通过修改yml里的连接信息来看看是否已生效。
如果觉得上面使用自定义配置的步骤复杂,可以使用简单方式,如下
@Bean
public RedisTemplate<String, String> getRedisTemplate(JedisConnectionFactory jedisConnectionFactory) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory);
//key序列化方式,但是如果方法上有Long等非String类型的话,会报类型转换错误
RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型不可以会出现异常信息;
redisTemplate.setKeySerializer(redisSerializer);
// redisTemplate.setHashKeySerializer(redisSerializer);
// redisTemplate.setValueSerializer(redisSerializer);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
该类只保留这一个方法就可以了,方法里加上参数JedisConnectionFactory,然后直接使用就行。上面定义的那些配置会被框架自动解释到这个参数里。效果和自己手工创建JedisConnectionFactory并设置参数是一样的。
该篇到此为止,下面还有几个问题需要考虑:
1.怎么处理db操作成功了,但操作redis失败。譬如刚才修改一下yml的ip地址,让redis连接不上,那么对db的操作还是会成功,但redis数据就不对了。
2.怎么操作集合数据,因为一个key对应一个集合转化的json字符串,是无法单独添加一条对象数据的,只能全失效或全成功,这样的话就不适合存储频繁改变的集合数据。
下篇来看看这些问题。
- .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”
- 全球15%工作将被自动化,中国1亿人将面临失业
- ASP.NET MVC的Model元数据提供机制的实现
- 清官难断家务事,人工智能却来介入家庭伦理大戏
- 使用Symfony的Console组件构建命令行程序
- 微软编程教育都在搞什么?从code.org到makecode,从Minecraft到Micro:bit
- 谷歌:通往完全自动驾驶之路
- 随时随地部署Kubernetes
- 使用CoreOs,Docker和Nirmata来部署微服务风格的应用程序
- 使用ACS和Kubernetes部署Red Hat JBoss Fuse
- 教你快速安装OpenShift容器平台3.6
- 面向开发者的Cloud Foundry
- 云数据库安全与农场和餐馆:知道来源的重要性
- 云数据库安全,农场和餐馆:知道你的来源的重要性
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- python爬虫--自动下载cosplay小姐姐图片(xpath使用自定义创建文件路径)
- springboot开发之修改员工
- LeetCode | 703.数据流中的第K大元素
- springboot开发之配置自定义的错误界面和错误信息
- springboot开发之删除员工
- LeetCode | 1.两数之和
- springboot开发之配置嵌入式Servlet容器两种方式
- jvaa之初始化块
- java之匿名内部类
- springboot配置之获取配置文件中属性的第二种方法(@Value)不同于@ConfigurationProperties
- mybatis动态sql之内置参数_parameter和_databaseId
- Redis | Redis 字符串相关命令
- java之抽象类
- springboot配置之yaml
- properties和yaml配置文件