开发过程中首次使用了redis,也是一点一点边学边开发,期间遇到了一些坑所以做下记录防止以后忘记。
首先代码里只用到了单机版的redis,但因为后续数据量的问题改成了集群版,这里记录集群版的基本配置,如果有不对的地方欢迎评论留言指正哈~
一、application.properties配置文件内容
首先在配置文件里写上配置redis集群的服务器和端口,这里用192.168.0.1、0.2、0.3三个服务器做集群。
spring.redis.cluster.nodes=192.168.0.1:7001,192.168.0.2:7002,192.168.0.3:7003
logging.config=classpath:logback-spring.xml
logging.level.com.test.service=debug
...
二、RedisConfig配置文件内容
这里是redis的配置类信息
@Configuration
public class RedisConfig {
@Value("${spring.redis.cluster.nodes}")
private String nodes;
@Bean
public RedisTemplate<String, Object> redisTemplateObject() throws Exception {
RedisTemplate<String, Object> redisTemplateObject = new RedisTemplate<String, Object>();
redisTemplateObject.setConnectionFactory(redisConnectionFactory());
setSerializer(redisTemplateObject);
redisTemplateObject.afterPropertiesSet();
return redisTemplateObject;
}
@Bean
public RedisConnectionFactory redisConnectionFactory(){
JedisPoolConfig poolConfig=new JedisPoolConfig();
//poolConfig.setMaxIdle(maxIdl);
//poolConfig.setMinIdle(minIdl);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
poolConfig.setTestWhileIdle(true);
poolConfig.setNumTestsPerEvictionRun(10);
poolConfig.setTimeBetweenEvictionRunsMillis(60000);
//JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisConfig(), poolConfig);
//jedisConnectionFactory.setHostName(hostName);
//jedisConnectionFactory.setPort(port);
//jedisConnectionFactory.setDatabase(database);
jedisConnectionFactory.setTimeout(100000);
return jedisConnectionFactory;
}
private void setSerializer(RedisTemplate<String, Object> template) {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setKeySerializer(template.getStringSerializer());
//template.setValueSerializer(jackson2JsonRedisSerializer);
//template.setHashValueSerializer(jackson2JsonRedisSerializer);
//在使用String的数据结构的时候使用这个来更改序列化方式
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
//template.setKeySerializer(stringSerializer );
template.setValueSerializer(stringSerializer );
//template.setHashKeySerializer(stringSerializer );
template.setHashValueSerializer(stringSerializer );
}
@Bean
public RedisClusterConfiguration jedisConfig(){
RedisClusterConfiguration config = new RedisClusterConfiguration();
String[] nodeArr = nodes.split(",");
List<RedisNode> nodeList = new ArrayList<>(nodeArr.length);
String[] tem;
for (String node : nodeArr){
tem = node.split(":");
nodeList.add(new RedisNode(tem[0], Integer.valueOf(tem[1])));
}
config.setClusterNodes(nodeList);
return config;
}
@Bean
public JedisCluster getJedisCluster(){
String[] nodeArr = nodes.split(",");
Set<HostAndPort> nodeSet = new HashSet<>();
String[] tem;
for (String node : nodeArr){
tem = node.split(":");
nodeSet.add(new HostAndPort(tem[0], Integer.valueOf(tem[1])));
}
return new JedisCluster(nodeSet);
}
}
三、集群中不能使用pipeline操作的解决方法
把redis单机版改为集群后,原本单机版代码里使用pipeline进行批量操作入库的代码就不能使用了。会提示提示org.springframework.data.redis.connection.jedis
.JedisClusterConnection错误。
上网查了之后知道是pipeline不能在集群模式下使用的原因,但是不使用批量操作的话循环入库的速度又会受到影响。所以只能重写pipeline的方法,实现原来管道的操作。使用的是该链接里的重写类JedisClusterPipeline,直接拿过来用就可以。
https://blog.csdn.net/EndTheme_Xin/article/details/84623063
下面是单机版和集群版批量操作的代码对比
原来单机版的批量入库代码:
List<Object> list = redisTemplate.executePipelined(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
redisConnection.openPipeline();
for (String server : ipList){
String key = server.split("|")[0];
String value = server.split("|")[1];
redisConnection.hSet(dateStr.getBytes(), key.getBytes(), value.getBytes());//dateStr是日期。
redisConnection.expire(dateStr.getBytes(), expireTime);//expireTime是过期时间(秒)。
}
}
}, redisTemplate.getValueSerializer());
改成集群后的批量入库代码:
JedisClusterPipeline jcp = JedisClusterPipeline.pipelined(jedisCluster);//jedisCluster是配置类里声明的Bean
jcp.refreshCluster();
List<Object> batchResult = null;
try {
for (String server : ipList){
String key = ...;
String value = ...;
jcp.setex(key, expireTime.intValue(), value);//expireTime是过期时间(秒)
}
jcp.sync();
batchResult = jcp.syncAndReturnAll();
} finally {
jcp.close();j
}
PS(额外记录)
在一个类中引用properties文件里值的写法
@PropertySource(value = {"classpath:/config.properties",
"file:${spring.profiles.path}/config.properties"}, ignoreResourceNotFound = true)
public class Test{
@Value("${log_path}")
private String logPath;
......
@Scheduled(cron = "${cron_expression}")
public void task(){
......
}
}