美文网首页
9 springboot集成redis

9 springboot集成redis

作者: lijiaccy | 来源:发表于2017-12-04 10:46 被阅读0次

    redis分两种,一种单机 http://www.jianshu.com/p/6ac1a3b7745e,一种集群 http://www.jianshu.com/p/d44aa9a8be2c
    首先看spring操作redis的配置,我项目只用到这些,其他的自行百度。
    首先添加依赖包

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
    

    然后写类RedisClient

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.geo.Circle;
    import org.springframework.data.geo.Distance;
    import org.springframework.data.geo.Metrics;
    import org.springframework.data.geo.Point;
    import org.springframework.data.redis.connection.RedisGeoCommands;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Component;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    
    @Component
    public class RedisClient {  
    
        @Autowired
        private RedisTemplate redisTemplate;
          //set值
        public void set(String key, String value) {
            try {
                redisTemplate.opsForValue().set(key,value);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
          //get值
        public String get(String key) {
    
            try {
                return ""+redisTemplate.opsForValue().get(key);
            }catch (Exception e){
                e.printStackTrace();
                return "";
            }
        }
       //自增1
        public void incr(String key) {
            int num = Integer.parseInt(""+redisTemplate.opsForValue().get(key));
            num=num+1;
            redisTemplate.opsForValue().set(key,num);
        }
       //到期时间
        public boolean expire(String key, int second) {
            boolean result = redisTemplate.expire(key,second, TimeUnit.SECONDS);
            return result;
        }
    
       //删除
        public void del(String key) {
            redisTemplate.delete(key);
        }
       //是否存在key
        public boolean hasKey(String s) {
            Boolean flag =  redisTemplate.hasKey(s);
            return flag;
    
        }
       //左push
        public boolean lpush(String key, String value){
            boolean flag =false;
            try{
                redisTemplate.boundListOps(key).leftPush(value);
                flag =true;
            }catch (Exception e){
                e.printStackTrace();
            }
            return flag;
    
        }
        //右push
        public boolean rpush(String key, String value){
            boolean flag =false;
            try{
                redisTemplate.boundListOps(key).rightPush(value);
                flag =true;
            }catch (Exception e){
                e.printStackTrace();
            }
            return flag;
    
        }
       //添加附近的人
        public boolean geoadd(String key,double longitude,double latitude){
            boolean flag = false;
            try{
                redisTemplate.boundGeoOps("nearPeople").geoAdd(new Point(longitude,latitude),key);
                flag = true;
            }catch (Exception e){
                e.printStackTrace();
            }
    
            return flag;
        }
       //查询附近的人
        public List geoQuery(double longitude,double latitude) {
            List  list = null;
            try{
                list = redisTemplate.opsForGeo().geoRadius("nearPeople", new Circle(new Point(longitude, latitude),
                        new Distance(500,Metrics.KILOMETERS)),
                        RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates()).getContent();
    
            }catch (Exception e){
                e.printStackTrace();
            }
    
            return list;
        }
    }
    

    注意:

    我用的是RedisTemplate,在这之前我用的是redis.clients.jedis.JedisPool,但是每次操作就第一次,可以,稍微快速刷新两次就一直阻塞,代码

    public void set(String key, String value) {
        Jedis jedis = null;
        try {  
            jedis = jedisPool.getResource();  
            jedis.set(key, value);  
        } finally {  
            //返还到连接池  
            jedis.close();  
        }  
    }  
    

    具体原因没弄明白,好像和最大连接数有关,之后发现不行,才换成RedisTemplate

    单机配置

    配置文件application.properties添加

    # Redis数据库索引(默认为0)
    spring.redis.database=0
    # Redis服务器地址
    spring.redis.host=172.16.255.231
    # Redis服务器连接端口
    spring.redis.port=6379
    # Redis服务器连接密码(默认为空)
    spring.redis.password=
    # 连接池最大连接数(使用负值表示没有限制)
    spring.redis.pool.max-active=8
    # 连接池最大阻塞等待时间(使用负值表示没有限制)
    spring.redis.pool.max-wait=-1
    # 连接池中的最大空闲连接
    spring.redis.pool.max-idle=8
    # 连接池中的最小空闲连接
    spring.redis.pool.min-idle=1
    # 连接超时时间(毫秒)
    spring.redis.timeout=5000
    

    类Controller中测试

    @Controller
    @RequestMapping("/hello")
    public class HelloController {
    
    @Autowired
    private HelloService helloService;
    @Autowired
    private RedisClient redisClient;
    @RequestMapping(value = "/testRedis",method = RequestMethod.GET)
    @ResponseBody
    public String testRedis(@RequestParam String userId){
        if (redisClient.hasKey(userId)){
            System.out.println("redis中用户存在");
            return redisClient.get(userId);
        }
        User user = new User();
        user.setId("1");
        user.setUsername("lijia");
    
        redisClient.set(userId,JSON.toJSONString(user));
        System.out.println("redis中用户不存在,现在已设定");
        return JSON.toJSONString(user);
    }
    }
    

    启动Application,然后再浏览器中输入 http://localhost:8080/hello/testRedis?userId=1
    两次都能返回结果,但是一次是从redis中读取的,一次是直接获取的


    这样redis单机环境就搭建好了。

    集群配置

    还是修改application.properties

    spring.redis.cluster.nodes=172.16.255.231:7001,172.16.255.231:7002,172.16.255.231:7003,172.16.255.231:7004,172.16.255.231:7005,172.16.255.231:7006
    

    然后读取这个配置文件

    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Configuration;
    import java.util.ArrayList;
    import java.util.List;
    @Configuration
    @ConfigurationProperties(prefix = "spring.redis.cluster")
    public class RedisClusterProperties {
        //集群节点
        private List<String> nodes=new ArrayList<>();
        public List<String> getNodes() {
            return nodes;
        }
        public void setNodes(List<String> nodes) {
            this.nodes = nodes;
        }
    }
    

    配置

    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.util.Assert;
    import org.springframework.util.StringUtils;
    import redis.clients.jedis.HostAndPort;
    import redis.clients.jedis.JedisCluster;
    import javax.annotation.Resource;
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.Set;
    
    @Configuration
    @ConditionalOnClass(RedisClusterConfig.class)
    @EnableConfigurationProperties(RedisClusterProperties.class)
    public class RedisClusterConfig {
        @Resource
        private RedisClusterProperties redisClusterProperties;
        @Bean
        public JedisCluster redisCluster(){
            Set<HostAndPort> nodes = new HashSet<>();
            for (String node:redisClusterProperties.getNodes()){
                String[] parts= StringUtils.split(node,":");
                Assert.state(parts.length==2, "redis node shoule be defined as 'host:port', not '" + Arrays.toString(parts) + "'");
                nodes.add(new HostAndPort(parts[0], Integer.valueOf(parts[1])));
            }  
            return new JedisCluster(nodes);
        }
    }
    

    最后还是测试类,上面的一样,但是判断key方式不一样

    import com.alibaba.fastjson.JSON;
    import com.lijia.bean.User;
    import com.lijia.service.HelloService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    import redis.clients.jedis.JedisCluster;
    
    @Controller
    @RequestMapping("/hello")
    public class HelloController {
        @Autowired
        private HelloService helloService;
        @Autowired
        private JedisCluster jedisCluster;
        @RequestMapping(value = "/testRedis",method = RequestMethod.GET)
        @ResponseBody
        public String testRedis(@RequestParam String userId){
            if (jedisCluster.exists(userId)){
                System.out.println("redis集群中用户存在");
                return jedisCluster.get(userId);
            }
            User user = new User();
            user.setId("1");
            user.setUsername("lijia");
            jedisCluster.set(userId,JSON.toJSONString(user));
            System.out.println("redis集群中用户不存在,现在已设定");
            return JSON.toJSONString(user);
        }
    
    }
    

    启动Application,然后再浏览器中输入 http://localhost:8080/hello/testRedis?userId=1
    两次都能返回结果,但是一次是从redis中读取的,一次是直接获取的


    这集群算是可以用了。
    注意:
    今天再用linux中连接redis,发现连接集群中,需要加上-c,这个是必须的,不然set和get报错。

    JedisPool假死

    如果用jedisPool去set和get。首先会有一段jedis = jedisPool.getResource();
    就是当连接池耗尽的时候

    BlockWhenExhausted:连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
    max-wait:获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常,小于零:阻塞不确定的时间, 默认-1

    由于BlockWhenExhausted默认为true,连接耗尽时会阻塞到超时,但是MaxWaitMillis默认为-1,超时时间是一个不确定的时间,所以就一直阻塞着了。
    设置redis.pool.max-wait值。

    RedisTemplate乱码现象

    使用了RedisTemplate之后,今天测试之后发现redis找不到key,但是出现了下面这种情况。


    原因是:
    spring-data-redis的RedisTemplate<K, V>模板类在操作redis时默认使用JdkSerializationRedisSerializer来进行序列化

    因为spring操作redis是在jedis客户端基础上进行的,而jedis客户端与redis交互的时候协议中定义是用byte类型交互,jedis中提供了string类型转为byte[]类型,
    但是看到spring-data-redis中RedisTemplate<K, V>在操作的时候k,v是泛型的,所以RedisTemplate中有了上面那段代码,在没有特殊定义的情况下,
    spring默认采用defaultSerializer = new JdkSerializationRedisSerializer();来对key,value进行序列化操作。

    把原来的

    @Autowired
    private RedisTemplate redisTemplate;
    

    修改为:

    private RedisTemplate redisTemplate;
    @Autowired(required = false)
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(stringSerializer);
        this.redisTemplate = redisTemplate;
    }
    

    然后再试试就好了。

    相关文章

      网友评论

          本文标题:9 springboot集成redis

          本文链接:https://www.haomeiwen.com/subject/nhutixtx.html