开发过程中首次使用了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(){
        ......
    }    
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐