Redis整合springboot笔记

文章详细介绍了如何在SpringBoot项目中整合Redis,包括添加依赖、配置连接参数,以及使用StringRedisTemplate操作Redis的各种数据类型,如字符串、列表、集合、有序集合和地理位置。同时,文章还展示了如何进行消息发布和订阅,以及设置key过期监听。
摘要由CSDN通过智能技术生成

redis整合springboot学习笔记

pom引入依赖

需要同时引入spring-boot-starter-data-redis和commons-pool2这2个依赖;
spring-boot-starter-data-redis是官方封装的redis操作依赖,
commons-pool2是redis需要的连接池,不引入这个会导致启动报错.

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.5.0</version>
        </dependency>

配置springboot项目内的application.yml或application.properties

spring:
  redis:
    # ip
    host: localhost
    # 端口6379
    port: 6379
    #密码,没有密码则不配置这一项
    password:
    #指定使用redis 16个库中的哪一个,不配置的话,默认配置为0
    database: 0
    lettuce:
      pool:
        min-idle: 0   #连接池最新空闲时间
        max-wait: -1ms  #最大等待时间
        max-active: 8   #最大活跃时间
        max-idle: 8    #最大空闲时间
      shutdown-timeout: 100ms  #连接池关闭超时时间
    timeout: 1000ms  #redis连接超时时间

使用spring-boot-starter-data-redis内置的StringRedisTemplate

要在需要使用redis的地方注入StringRedisTemplate,如

@Slf4j
@Component
@Validated
public class RedisTool {
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }
    private ObjectMapper objectMapper;
     @Autowired
    public void setObjectMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

}    

StringRedisTemplate 是springDataRedis提供的一个模板类,可以让我们更方便的操作key值类型为字符串的Redis Key 。

redis各种数据类型的使用场景

请添加图片描述

请添加图片描述

字符串类型是Redis最基础的数据结构,字符串类型的值实际可以是字符串(简单的字符串、复杂的字符串(例如JSON、XML))、数字(整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能超过512MB。

请添加图片描述

请添加图片描述
请添加图片描述

请添加图片描述

StringRedisTemplate 内提供的常用的方法如下。

判断key是否存在

 public boolean hasKey(@NotNull String strK) {
        Boolean hasKey = stringRedisTemplate.hasKey(strK);
        if (hasKey != null && hasKey) {
            return true;
        } else {
            log.warn("不存在redis key:{}",strK);
            return false;
        }
    }

删除key

//删除1个key
public void deleteOneKeyIfExist(@NotNull String key) {
        if (this.hasKey(key)) {
            Boolean delete = stringRedisTemplate.delete(key);
            log.info("删除了key:{},删除结果:{}",key, delete);
        }
    }

//删除多个key
public void deleteBatchKeyIfExist(Set<String> keySet) {
        for (String k : keySet) {
            this.deleteOneKeyIfExist(k);
        }
    }    

添加key

//添加固定的key
public void setKV(@NotNull String strK, String plainStrV) {
        stringRedisTemplate.opsForValue().set(strK, plainStrV);
    }
//添加带超时时间的key,超时时间到期后key会自动删除
    public void setKVTimeoutSeconds(@NotNull String strK, String plainStrV, long seconds) {
        stringRedisTemplate.opsForValue().set(strK, plainStrV, seconds, TimeUnit.SECONDS);
    }
    
    //序列化后 进行set key
    public boolean setKeyAndObjValue(@NotNull String strK, @NotNull Object objV) {
        try {
            String s = objectMapper.writeValueAsString(objV);
            log.warn("jackson序列化:{}", s);
            this.setKV(strK, s);
            return true;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            log.error("jackson序列化失败", e);
            return false;
        }
    }


    public boolean setKeyAndObjValueByTimeoutSeconds(@NotNull String strK, @NotNull Object objV, long seconds) {
        try {
            String s = objectMapper.writeValueAsString(objV);
            log.warn("jackson序列化:{}", s);
            this.setKVTimeoutSeconds(strK, s, seconds);
            return true;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            log.error("jackson序列化失败", e);
            return false;
        }
    }

查询key


//获取key的字符串值
public String getPlainStrV(@NotNull String srtKey) {
        if (!this.hasKey(srtKey)) {
            return null;
        }
        return stringRedisTemplate.opsForValue().get(srtKey);
    }

//获取key的对象值
    public <T> T getJavaObjByJsonCache(@NotNull String srtKey, Class<T> valueType) {
        if (!this.hasKey(srtKey)) {
            return null;
        }
        String str = stringRedisTemplate.opsForValue().get(srtKey);
        if (StrUtil.isBlank(str)) {
            return null;
        }
        try {
            log.warn("反序列化json str:{} 为Java obj type:{}", str,valueType);
            return objectMapper.readValue(str, valueType);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("json str 反序列化失败", e);
            return null;
        }
    }

随机获取一个key

//随机取一个 redis key名
    public String getRandomKey(){
        return stringRedisTemplate.randomKey();
    }

加1/减1/替换-操作

stringRedisTemplate.opsForValue().set("wfew", "233");
//+1和减1操作 (key不存在时,创建这个key,并设置为指定的值;key存在时,直接设置key值加1或减1)
 //+1操作 
 stringRedisTemplate.boundValueOps("twfew").increment(1);  //key不存在,存入一个key值1
  //-1操作 
 stringRedisTemplate.boundValueOps("wfew").decrement(1); //值变为232
 //替换操作 设置新值,同时返回旧值 (key不存在依然可以操作)
  String oldVal = stringRedisTemplate.boundValueOps("kwfew").getAndSet("500");       System.out.println(oldVal);//不存在旧值,返回null

设置几秒过期

//设置几秒过期
        stringRedisTemplate.opsForValue().set("gb23f", "gwr23", 100, TimeUnit.SECONDS);

查询当前key还剩几秒过期

Long gb23f = stringRedisTemplate.getExpire("gb23f", TimeUnit.SECONDS);
System.out.println(gb23f);

覆盖key值并设置过期时间

//已存在的固定key,会被设置新值同时设置过期时间
        stringRedisTemplate.boundValueOps("wfew").set("300", 60, TimeUnit.SECONDS);

append拼接key值

stringRedisTemplate.opsForValue().set("th718", "718");
 //append拼接key值
stringRedisTemplate.boundValueOps("th718").append("23");
  //打印71823
System.out.println(stringRedisTemplate.opsForValue().get("th718"));     

获取旧值,同时set新值

//获取旧值,同时set新值,若旧值不存在会返回null
String th718 = stringRedisTemplate.opsForValue().getAndSet("th718", "202307");
//会打印 71823
System.out.println(th718);

仅在键不存在时设置key

//setIfAbsent-仅在键不存在时设置key, 相当于redis中的setnx命令
        //  key存在则不变,key不存在则执行set;
        //  返回true表示key不存在,set了一个新key
        //  返回false表示key已存在,不进行set
        //适合场景:并发环境下的分布式锁--(多个进程/线程尝试设置同一个key,set成功则表示获取到锁,set失败表示没有获取到锁)
        //setIfAbsent是一个原子性操作,分布式环境下需要注意并发问题和过期时间的处理
Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent("th720", "kwerq2");
System.err.println(aBoolean);

批量获取key值

//批量获取key值
List<String> stringList = stringRedisTemplate.opsForValue().multiGet(
                ListUtil.toList("th718", "th719", "th720","th721"));
  //某个key不存在,则值获取为null
  //[202307, 202307170, kwerq, null]
System.err.println(stringList);

操作list结构

redis list 中的元素可以重复 ,且list元素是有序的.

redis list 的结构类似于队列, 提供了lpush左入队,rpop右出队 相关的方法, 但不建议使用redis的List作为队列使用.

redis列表的使用场景包括消息队列、发布/订阅、实时排行榜、历史记录、消息通知系统、简单队列等场景

push 向list中添加元素

  
        //right push 操作 可以创建key并向右顺序插入元素,或者在已有list的末尾追加元素
        stringRedisTemplate.opsForList().rightPush("lst1", "hjew");
        stringRedisTemplate.opsForList().rightPush("lst1", "bswgrg");
        stringRedisTemplate.opsForList().rightPush("lst1", "hjew");
        stringRedisTemplate.opsForList().rightPush("lst1", "kgwefqz");
        // left push 操作, 可以创建key并向左插入元素,或者在已有list的第一个元素之前追加元素
        stringRedisTemplate.opsForList().leftPush("lst1", "gtw1e");
        stringRedisTemplate.opsForList().leftPush("lst1", "nkqwe1");

pop 弹出list中的元素

stringRedisTemplate.opsForList().rightPush("lst2", "v1");
stringRedisTemplate.opsForList().rightPush("lst2", "v2");
stringRedisTemplate.opsForList().leftPush("lst2", "zisj");
     //从 lst2 列表 中最后一个元素开始,弹出1个元素 
    //[从右往左删除元素 (或删除列表中最后一个元素)]
stringRedisTemplate.opsForList().rightPop("lst2");

//从左往右删除元素 (或删除列表中第一个元素)
stringRedisTemplate.opsForList().leftPop("lst2");

仅在键不存在时向list添加元素

// 若 lst3 这个key存在,则 向左插入1个元素 (lst3不存在则不会执行)
stringRedisTemplate.opsForList().leftPushIfPresent("lst3", "nkqwe1");
//创建lst3并向右 插入1个元素
stringRedisTemplate.opsForList().rightPush("lst3", "grt2r3");
// 若 lst3 这个key存在,则 向右 插入1个元素
stringRedisTemplate.opsForList().rightPushIfPresent("lst3", "hwerg");

根据索引来查询/更新/删除list中的元素

 // 获取lst1 列表中 索引为0的元素
System.err.println(stringRedisTemplate.opsForList().index("lst1", 0));
 // 对 lst1 列表中的 索引为 2的元素 ,设置为 e3;  (若lst1不存在,会报错 ERR no such key)
stringRedisTemplate.opsForList().set("lst1", 2, "e3");
// 仅当 列表 lst3 中 索引为1的元素 为  hwerg 时,才执行删除 这个元素
System.err.println(stringRedisTemplate.opsForList().remove("lst3", 1, "hwerg"));

对list里的元素进行范围查询

// 范围查询 ,获取 lst1 列表中 ,索引从1到4的元素
List<String> rangeList = stringRedisTemplate.opsForList().range("lst1", 1, 4);
System.err.println(rangeList);

操作set结构

redis 的Set是一个无序的、唯一的数据集合。

无序性:集合中的元素没有固定顺序,每次获取的元素顺序可能不同
唯一性:集合中的元素是唯一的,不允许重复
添加元素:sadd 命令
删除元素: srem命令
查找元素: sismember命令
获取元素的数量: scard命令
获取所有元素: smembers命令
set集合间的操作: sinter求交集 \sunion 求并集\ sdiff 求差集

set集合的实际使用场景有:

去重:把java集合放入redis set,实现去重
共同好友/共同关注 : 2个集合求交集可以实现
标签或分类:用set集合存在对象的标签或分类,方便快速查找
排他性操作:通过求差集,实现对范围外的用户进行排他性操作

在springDataRedis里提供了一下对redisSet的操作方法如下

@Test
    public void testSet() {
//创建一个无序集合,并写入数据 (set中的元素不能重复, 若values里的元素有重复的,写入时会自动去重)
stringRedisTemplate.opsForSet().add("sk1", "reg23r", "r23rf", "kuy54rt", "hn5t4t","reg23r");
        //判断set中是否存在某个元素
        System.out.println(
                stringRedisTemplate.opsForSet().isMember("sk1", "reg23r"));
        //根据key获取set中的元素
        System.out.println(
                stringRedisTemplate.opsForSet().members("sk1"));

        //从1个set中随机取3个元素
        System.out.println(stringRedisTemplate.opsForSet().distinctRandomMembers("sk1", 3));
        //从1个set中随机取1个元素
        System.out.println(stringRedisTemplate.opsForSet().randomMember("sk1"));

        //从1个set中删除 某些元素
        stringRedisTemplate.opsForSet().remove("sk1", "ga34rerw", "greg23");


        stringRedisTemplate.opsForSet().add("sk2", "plf23e", "r23rf");
        System.out.println(
                stringRedisTemplate.opsForSet().members("sk2"));
        // sk1 集合 减去 sk2 集合
        System.err.println(stringRedisTemplate.opsForSet().difference("sk1", "sk2"));
        // sk2 减 sk1
        System.err.println(stringRedisTemplate.opsForSet().difference("sk2", "sk1"));
        // 2个set集合相减,结果存到新的set中
      stringRedisTemplate.opsForSet().differenceAndStore("sk1", "sk2", "sk3");

        //两个set集合求交集
      System.err.println(stringRedisTemplate.opsForSet().intersect("sk1", "sk2"));
        //两个set集合求交集, 结果存到新的set中
      stringRedisTemplate.opsForSet().intersectAndStore("sk1", "sk2", "sk5");

        //2个set集合 求并集
      System.err.println(stringRedisTemplate.opsForSet().union("sk1", "sk2"));
        //sk1和sk2 求并集,然后结果存到sk8里
      stringRedisTemplate.opsForSet().unionAndStore("sk1", "sk2", "sk8");


        //移动1个元素 到1个新的set
        //把sk1里的元素hn5t4t,移动到sk6
      System.out.println(stringRedisTemplate.opsForSet().move("sk1", "hn5t4t", "sk6"));

        //获取1个set的元素数目
      System.err.println(stringRedisTemplate.opsForSet().size("sk1"));

    }

操作zset结构

zset是redis里的的有序集合,是一种允许存储多个元素并对每个元素设置一个score分数的数据结构

zset的特点:
排序性: zset 数据最终存储的顺序是按照score得分从低到高排序,如果score相同再按成员的字典顺序排序。
 唯一性: zset中的元素是唯一的,不允许重复
   添加元素和分数的命令: zadd
   删除元素的命令: zrem
    获取元素的分数: zscore
   统计zset元素数目: zcard
   根据分数范围和排名获取成员: zrangebyscore / zrank
  集合间的操作: zinterstore 求交集 /zunionstore 求并集
        
  zset的使用场景:
          排行榜:根据得分进行排名/获取排行
          范围查询: 根据得分进行范围查询
          任务优先级: 可以用得分来表示任务优先级 或 权重 ,进行按优先级/权重 的调度
          社交网络: 可以用zset存用户之间的关系和相关指标,如共同关注的人、好友推荐等

springDataRedis提供的常用的对zset的操作如下

@Test
    public void testZset() {        
        redisTool.deleteBatchKeyIfExist(Stream.of("zs1", "zs2", "zs3").collect(Collectors.toSet()));
        // 创建zs1 集合 , 同时写入 元素值 及其 得分;
        // (redis zset 数据最终存储的顺序是按照score得分从低到高排序)
        stringRedisTemplate.opsForZSet().add("zs1", "v01", 0.3);
        stringRedisTemplate.opsForZSet().add("zs1", "v03", 0.5);
        stringRedisTemplate.opsForZSet().add("zs1", "v07", 0.2);
        stringRedisTemplate.opsForZSet().add("zs1", "v09", 0.2);
        stringRedisTemplate.opsForZSet().add("zs1", "v12", 0.1);
        // 统计分数为0.1到0.3 的元素数目
        //这里打印结果是 4
        System.out.println(stringRedisTemplate.opsForZSet().count("zs1", 0.1, 0.3));

        // 获取 zset中 索引从 1到3 的集合
        // 由于zset 数据最终存储的顺序是按照score得分从低到高排序,
        // 所以 索引1-3的数据 是  [v07, v09, v01]
        Set<String> rangeSet = stringRedisTemplate.opsForZSet().range("zs1", 1, 3);
        System.out.println(rangeSet);

        //对索引1-3的数据 倒序排序
        Set<String> zs12 = stringRedisTemplate.opsForZSet().reverseRange("zs1", 1, 3);
        //[v01, v09, v07]
        System.err.println(zs12);


        //按score分数范围 查询元素集合
        //查询score在0.1到0.3 的元素集合
        Set<String> zs1 = stringRedisTemplate.opsForZSet().rangeByScore("zs1", 0.1, 0.3);
        //[v12, v07, v09, v01]
        System.out.println(zs1);

        //score在0.1到0.3 的元素 倒序排序
        Set<String> zs13 = stringRedisTemplate.opsForZSet().reverseRangeByScore("zs1", 0.1, 0.3);
        //[v01, v09, v07, v12]
        System.out.println(zs13);


        //查询某个元素的排行(即zet中某个元素的索引)
        Long zs11 = stringRedisTemplate.opsForZSet().rank("zs1", "v03");
        //v03的索引是4 ,这里会打印 4
        System.out.println(zs11);

        //查询某个元素排倒数第几 (即倒序索引)
        Long aLong = stringRedisTemplate.opsForZSet().reverseRank("zs1", "v03");
        System.out.println(aLong);

        //重新设置某元素的score得分
        //incrementScore 加分 (在原有基础上增加多少得分)
        Double aDouble = stringRedisTemplate.opsForZSet().incrementScore("zs1", "v09", 0.40);
        //0.2 +0.40 = 0.6
        //打印结果是 0.6
        System.out.println(aDouble);

        //再次打印zset 索引0-5的元素
        Set<String> zs14 = stringRedisTemplate.opsForZSet().range("zs1", 0, 5);
        //[v12, v07, v01, v03, v09]
        System.out.println(zs14);

}

操作hash结构

redis里的 hash用于存储 键值对的集合, 需要注意的是 hash 元素中的键和值 都是字符串类型
redis里的 hash 提供了类似于 字典或关联数组的功能,可以通过键 快速访问和修改对应的值

  redis 哈希的特点:
           存储结构: 类似于java里的map ,以键值对形式存储数据
             键的唯一性: hash中的 hashKey是唯一的,不允许重复
             添加键值对命令: hset
              获取值命令: hget
            删除键值对命令: hdel
              获取所有键值对: hgetall
             获取所有键和值: hkeys / hvals
             统计键值对数量: hlen

  redis hash结构的使用场景包括:
        对象存储:hash可以表示对象,其中对象的字段存储为hash的键值对
          用户属性存储: 可以将用户的属性存储在hash中,通过键来快速获取用户的相应属性
         数据库模型存储: 可以用hash存储关系数据库表的行记录,其中每行的字段对应hash的键值对

springDataRedis提供的常用的对hash的操作如下

@Test
    public void testhash() {       
        redisTool.deleteBatchKeyIfExist(Stream.of("htb1", "htb2", "htb3").collect(Collectors.toSet()));

        HashOperations<String, Object, Object> sooHashOperations = stringRedisTemplate.opsForHash();
        //put方法: 对某个redis key里添加键值对 ,键是hashKey ,值是value
        sooHashOperations.put("htb1", "hk001", "er21r12r");
        sooHashOperations.put("htb1", "hk002", "3rge");
        sooHashOperations.put("htb1", "hk003", "tgr");
        sooHashOperations.put("htb1", "hk004", "er21r12r");
        sooHashOperations.put("htb1", "hk005", "erg23");

        sooHashOperations.put("htb2", "hk201", "er21r12r");
        sooHashOperations.put("htb2", "hk202", "ret234t");
        sooHashOperations.put("htb2", "hk203", "gr34r");
        sooHashOperations.put("htb2", "hk204", "n818gr34r");

        //size方法: 统计hash中的键值对数量
        Long htb11 = sooHashOperations.size("htb1");
        //5
        System.out.println(htb11);

        Map<String, Object> htb3 = new HashMap<>();
        htb3.put("ewfeqf", "r32r23r");
        htb3.put("hethrt", "n1498h4");
        //putAll方法: 可以直接把java里的 HashMap 放入redis hash中缓存
        sooHashOperations.putAll("htb3", htb3);

        //hasKey 方法: 判断某个redis key里 是否存在键名为 hk001的元素
        //true
        System.err.println(sooHashOperations.hasKey("htb1", "hk001"));

        //entries方法: 查询redis key名为 htb1 的所有键值对
        Map<Object, Object> htb1 = sooHashOperations.entries("htb1");
        //{hk001=er21r12r, hk002=3rge, hk003=tgr, hk004=er21r12r, hk005=erg23}
        System.out.println(htb1);
        //false
        System.err.println(htb1.containsKey("hk203"));

        //multiGet方法: 同时查询多个hashKey
        List<Object> objects = sooHashOperations.multiGet("htb1", ListUtil.toList("hk001", "hk002"));
        //[er21r12r, 3rge]
        System.err.println(objects);


        //get方法: 获取某个redis key里的键名为 hk001的元素值
        Object o = sooHashOperations.get("htb1", "hk001");
        //er21r12r
        System.out.println(o);

        //delete方法: 删除某个redis key里的 某些键值对 , hashKeys表示可以传入多个键名
        //打印结果为2 ,表示成功删除了2个hashKey
        System.err.println(sooHashOperations.delete("htb2", "hk201", "hk202"));



        //keys方法: 获取redis key名为 htb2 的hash键值对里的 key键集合
        Set<Object> keysForhtb2 = sooHashOperations.keys("htb2");
        //[hk203, hk204]
        System.out.println(keysForhtb2);

        //values方法: 获取redis key名为 htb2 的hash键值对里的 value值集合
        List<Object> htb2 = sooHashOperations.values("htb2");
        //[gr34r, n818gr34r]
        System.out.println(htb2);

    }

操作geo数据结构

redis geo 是一种地理位置存储结构

redis 3.2版本开始有了geo这个数据结构,可以存储/查询地理位置信息

redis geo的常用命令:
  添加地理位置:
      geoadd  g1  93.21   26.32  shanghai;geoadd  g1  87.12   35.23  beijing;
  获取地理位置:
      geopos  g1  shanghai;
  计算距离:
      geodist g1 shanghai beijing km;
删除地理位置: zrem
获取某个坐标点 半径多少km的范围内的成员:
      georadius g1 88.12 30.13 1500 km;
获取某个标识点 半径多少km的范围内的成员:
      georadiusbymember g1 beijing 2000 km;

 redis geo的使用场景包括:
  附近的人:可以根据用户的地理位置信息,查询附近的其他用户
  地理位置搜索: 根据经纬度信息,搜索特定地点附近的商店、餐厅等
  路径规划: 根据地理位置信息,计算两个地点之间的距离和最短路径

springDataRedis提供的常用的对geo的操作如下

@Test
    public void testGeo() {

        redisTool.deleteBatchKeyIfExist(Stream.of("g1", "g2", "g3").collect(Collectors.toSet()));

        //添加地理位置
        //向key名为g1的geo集合里添加一个Point坐标经纬度 和对应的member地理标识名
        stringRedisTemplate.opsForGeo().add("g1", new Point(23.12, 31.23), "m1");
        stringRedisTemplate.opsForGeo().add("g1", new Point(93.21, 26.32), "shanghai");
        stringRedisTemplate.opsForGeo().add("g1", new Point(87.12, 35.23), "beijing");
        //获取多个地理位置
        List<Point> position = stringRedisTemplate.opsForGeo()
                .position("g1", "m1","shanghai");
        //[Point [x=23.120001, y=31.229999], Point [x=93.210001, y=26.320001]]
        System.out.println(position);

        //计算距离
        Distance distance = stringRedisTemplate.opsForGeo()
                .distance("g1", "shanghai", "beijing",
                RedisGeoCommands.DistanceUnit.KILOMETERS);
        if (distance!=null){
            //1148.6266km
            System.out.println(distance.getValue() + distance.getUnit());
        }

        //获取某个坐标点 半径多少km的范围内的成员
        GeoResults<RedisGeoCommands.GeoLocation<String>> g1radius = stringRedisTemplate.opsForGeo()
                .radius("g1",
                        new Circle(
                            new Point(88.12, 30.13),
                            new Distance(1500, RedisGeoCommands.DistanceUnit.KILOMETERS)
                        )
                );
        System.out.println(g1radius);



        //获取某个标识点 半径多少km的范围内的成员
        GeoResults<RedisGeoCommands.GeoLocation<String>> radius = stringRedisTemplate.opsForGeo()
                .radius("g1",
                "beijing",
                new Distance(2000, RedisGeoCommands.DistanceUnit.KILOMETERS));
        //GeoResults: [averageDistance: 0.0, results: GeoResult [content: RedisGeoCommands.GeoLocation(name=beijing, point=null), distance: 0.0, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=shanghai, point=null), distance: 0.0, ]]
        System.out.println(radius);
        if (radius!=null && radius.getContent().size()>0){
            for (GeoResult<RedisGeoCommands.GeoLocation<String>> geoLocationGeoResult : radius.getContent()) {
                //beijing
                //shanghai
                System.out.println(geoLocationGeoResult.getContent().getName());
            }
        }


        //删除多个地理标识的位置
        Long count = stringRedisTemplate.opsForGeo().remove("g1", "m1","beijing");
        // 打印2 ,表示成功删除了2个地理标识的位置
        System.out.println(count);

    }

通过redis中的pub/sub实现消息发布和订阅

定义RedisPubSubCfg

package cn.test.redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;


@Configuration
public class RedisPubSubCfg {

   private final RedisConnectionFactory redisConnectionFactory;
   @Autowired
   public RedisPubSubCfg(RedisConnectionFactory redisConnectionFactory) {
       this.redisConnectionFactory = redisConnectionFactory;
   }

   /**
    * 将消息监听器绑定到消息容器
    * @return RedisMessageListenerContainer
    */
   @Bean
   public RedisMessageListenerContainer messageListenerContainer(){
       RedisMessageListenerContainer container = new RedisMessageListenerContainer();
       container.setConnectionFactory(redisConnectionFactory);

       //------分开订阅监听,使用自定义的消息监听器SubscribeListener-------
       //按名称匹配
       container.addMessageListener(new CitySub(),new ChannelTopic("cityTopic"));
       //按模式匹配
       container.addMessageListener(new TestSub(),new PatternTopic("/aaa/*"));

       return container;
   }

}

自定义消息监听器

package cn.test.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;

@Slf4j
public class TestSub implements MessageListener {
  
    @Override
    public void onMessage(Message message, byte[] pattern) {

        String s = new String(pattern);
        log.info("redis  sub pattern: "+s);

        String channelReal = new String(message.getChannel());
        log.info("real sub pattern: "+channelReal);

        String body = new String(message.getBody());
        log.info("TestSub 订阅到的消息: "+body);

    }
}


package cn.test.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;

@Slf4j
public class CitySub implements MessageListener {
  
    @Override
    public void onMessage(Message message, byte[] pattern) {
        String body = new String(message.getBody());

        String channel = new String(message.getChannel());
        System.err.println("Topic 名称: "+channel);
        String patternStr = new String(pattern);
        System.err.println("Topic 模式: "+patternStr);
        log.info("CitySub 订阅到的消息: {}",body);
    }
}

发布消息

springDataRedis中的stringRedisTemplate提供了convertAndSend方法可以发送消息。

@Test
    public void tstPublish() {
        String s = null;
        try {
            s = objectMapper.writeValueAsString(new CityInfo("aaa", 117.17, 31.52));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
//发送消息,topic为 cityTopic
        stringRedisTemplate.convertAndSend("cityTopic",
                s
        );
//发送消息,topic为 /aaa/123
        stringRedisTemplate.convertAndSend("/aaa/123",
                s
        );
    }
2023-07-19 19:32:42.003  INFO 1128 --- [erContainer-357] cn.test.redis.TestSub                    : redis  sub pattern: /aaa/*
2023-07-19 19:32:42.003  INFO 1128 --- [erContainer-357] cn.test.redis.TestSub                    : real sub pattern: /aaa/123
2023-07-19 19:32:42.003  INFO 1128 --- [erContainer-357] cn.test.redis.TestSub                    : TestSub 订阅到的消息: {"city":"hefei1689755562001","longitude":117.17,"latitude":31.52}

设置key过期监听

1.需要先配置 redis.conf ,开启key过期监听功能

notify-keyspace-events Ex

2.在springboot redis配置中,订阅key过期事件并发布pub/sub消息

@Configuration
public class RedisPubSubCfg {
    private final RedisConnectionFactory redisConnectionFactory;
    @Autowired
    public RedisPubSubCfg(RedisConnectionFactory redisConnectionFactory) {
        this.redisConnectionFactory = redisConnectionFactory;
    }
    /**
     * 将消息监听器绑定到消息容器
     * @return RedisMessageListenerContainer
     */
    @Bean
    public RedisMessageListenerContainer messageListenerContainer(){
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisConnectionFactory);
        //------分开订阅监听,使用自定义的消息监听器SubscribeListener-------
        //按名称匹配
        container.addMessageListener(new CitySub(),new ChannelTopic("cityTopic"));
        //按模式匹配
        container.addMessageListener(new TestSub(),new PatternTopic("/aaa/*"));


        //监听key过期事件,并发布一个消息
        //监听key过期事件 ,需要在redis.conf里开启配置 notify-keyspace-events Ex
        //然后需要在springDataRedis里订阅__keyevent@*__:expired 的模式消息
        container.addMessageListener(new ExpSub() ,new PatternTopic("__keyevent@*__:expired"));

        return container;
    }
}
package cn.test.redis.exp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
@Slf4j
public class ExpSub implements MessageListener {
    @Override
    public void onMessage(Message message, byte[] pattern) {
        String channelReal = new String(message.getChannel());
        log.info("real sub pattern: "+channelReal);

        String body = new String(message.getBody());
        log.info("过期的redisKey名: "+body);
    }
}
2023-07-19 19:32:41.090  INFO 1128 --- [erContainer-356] cn.test.redis.exp.ExpSub                 : real sub pattern: __keyevent@0__:expired
2023-07-19 19:32:41.090  INFO 1128 --- [erContainer-356] cn.test.redis.exp.ExpSub                 : 过期的redis key名: ewr3w1689755556001
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ThinkPet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值