9 springboot集成redis

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;
}

然后再试试就好了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容