Spring Boot 整合Redisson基础篇

摘要:介绍Redisson中分布式对象和集合的基础操作,包括对象桶、集合、列表和散列。

综述

  测试环境为:Spring Boot版本 2.5.x 和 Redisson 单机。关于如何中Spring Boot项目集成Redisson,请戳《Spring Boot 整合Redisson配置篇》。

  RedissonClient是线程安全的,由于其内部是通过Netty通信,所以除了同步执行方式,也支持异步执行。

Redisson 工具类

  首先提供一个Redisson 工具类,方便下文用于演示。

import org.redisson.api.*; import org.redisson.client.codec.StringCodec; import org.springframework.stereotype.Component;  import javax.annotation.Resource; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer;  @Component public class RedisUtils {      private RedisUtils() {     }      /**      * 默认缓存时间      */     private static final Long DEFAULT_EXPIRED = 32000L;      /**      * 自动装配redisson client对象      */     @Resource     private RedissonClient redissonClient;      /**      * 用于操作key      * @return RKeys 对象      */     public RKeys getKeys() {         return redissonClient.getKeys();     }     /**      * 移除缓存      *      * @param key      */     public void delete(String key) {         redissonClient.getBucket(key).delete();     }      /**      * 获取getBuckets 对象      *      * @return RBuckets 对象      */     public RBuckets getBuckets() {         return redissonClient.getBuckets();     }      /**      * 读取缓存中的字符串,永久有效      *      * @param key 缓存key      * @return 字符串      */     public String getStr(String key) {         RBucket<String> bucket = redissonClient.getBucket(key);         return bucket.get();     }      /**      * 缓存字符串      *      * @param key      * @param value      */     public void setStr(String key, String value) {         RBucket<String> bucket = redissonClient.getBucket(key);         bucket.set(value);     }      /**      * 缓存带过期时间的字符串      *      * @param key     缓存key      * @param value   缓存值      * @param expired 缓存过期时间,long类型,必须传值      */     public void setStr(String key, String value, long expired) {         RBucket<String> bucket = redissonClient.getBucket(key, StringCodec.INSTANCE);         bucket.set(value, expired <= 0L ? DEFAULT_EXPIRED : expired, TimeUnit.SECONDS);     }      /**      * string 操作,如果不存在则写入缓存(string方式,不带有redisson的格式信息)      *      * @param key     缓存key      * @param value   缓存值      * @param expired 缓存过期时间      */     public Boolean setIfAbsent(String key, String value, long expired) {         RBucket<String> bucket = redissonClient.getBucket(key, StringCodec.INSTANCE);         return bucket.trySet(value, expired <= 0L ? DEFAULT_EXPIRED : expired, TimeUnit.SECONDS);     }      /**      * 如果不存在则写入缓存(string方式,不带有redisson的格式信息),永久保存      *      * @param key   缓存key      * @param value 缓存值      */     public Boolean setIfAbsent(String key, String value) {         RBucket<String> bucket = redissonClient.getBucket(key, StringCodec.INSTANCE);         return bucket.trySet(value);     }      /**      * 判断缓存是否存在      *      * @param key      * @return true 存在      */     public Boolean isExists(String key) {         return redissonClient.getBucket(key).isExists();     }      /**      * 获取RList对象      *      * @param key RList的key      * @return RList对象      */     public <T> RList<T> getList(String key) {         return redissonClient.getList(key);     }      /**      * 获取RMapCache对象      *      * @param key      * @return RMapCache对象      */     public <K, V> RMapCache<K, V> getMap(String key) {         return redissonClient.getMapCache(key);     }      /**      * 获取RSET对象      *      * @param key      * @return RSET对象      */     public <T> RSet<T> getSet(String key) {         return redissonClient.getSet(key);     }      /**      * 获取RScoredSortedSet对象      *      * @param key      * @param <T>      * @return RScoredSortedSet对象      */     public <T> RScoredSortedSet<T> getScoredSortedSet(String key) {         return redissonClient.getScoredSortedSet(key);     }  } 

常用RKeys的API操作

  每个Redisson对象实例都会有一个与之对应的Redis数据实例,可以通过调用getName方法来取得Redis数据实例的名称(key)。所有与Redis key相关的操作都归纳在RKeys这个接口里:

RKeys keys = client.getKeys(); //获取所有key值 Iterable<String> allKeys = keys.getKeys(); //模糊查询所有包含关键字key的值 Iterable<String> foundedKeys = keys.getKeysByPattern(key); //删除多个key值 long numOfDeletedKeys = keys.delete(obj1, obj2, obj3); //模糊删除key值 long deletedKeysAmount = keys.deleteByPattern(test?); //随机获取key String randomKey = keys.randomKey(); //查询当前有多少个key long keysAmount = keys.count(); 

  具体demo如下:

   private void getKeys() {         RKeys keys = redisUtils.getRedisKeys();         Iterable<String> allKeys = keys.getKeys();         StringBuilder sb = new StringBuilder();         for (String key : allKeys) {             sb = sb.append(key).append(,);         }         log.info(所有的key:{}, sb.substring(0, sb.length() - 1));         // 模糊查询以 map 打头的所有 key         allKeys = keys.getKeysByPattern(map*);         sb = new StringBuilder();         for (String key : allKeys) {             sb = sb.append(key).append(,);         }         log.info(模糊匹配到的key:{}, sb.substring(0, sb.length() - 1));     } 

  其中,getKeysByPattern是基于redis 的 scan 命令实现的,匹配规则示例如下:

  • h?llo subscribes to hello, hallo and hxllo
  • h*llo subscribes to hllo and heeeello
  • h[ae]llo subscribes to hello and hallo, but not hillo

通用对象桶(Object Bucket)

  Redisson的分布式RBucket Java对象是一种通用对象桶,可以用来存放任意类型的对象。除了同步接口外,还提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。还可以通过RBuckets接口实现批量操作多个RBucket对象:

   /**      * String 数据类型      */     private void strDemo() {         redisUtils.setStr(DEMO_STR, Hello, String.);         log.info(String 测试数据:{}, redisUtils.getStr(DEMO_STR));         redisUtils.setStr(myBucket, myBucketIsXxx);         RBuckets buckets = redisUtils.getBuckets();         Map<String, String> foundBuckets = buckets.get(myBucket*);         Map<String, Object> map = new HashMap<>();         map.put(myBucket1, value1);         map.put(myBucket2, 30L);          // 同时保存全部通用对象桶。         buckets.set(map);         Map<String, String> loadedBuckets = buckets.get(myBucket1, myBucket2, myBucket3);         log.info(跨桶String 测试数据:{}, loadedBuckets);         map.put(myBucket3, 320L);     } 

散列(Hash)

  基于Redisson的分布式映射结构的RMap Java对象实现了java.util.concurrent.ConcurrentMap接口和java.util.Map接口。与HashMap不同的是,RMap保持了元素的插入顺序。该对象的最大容量受Redis限制,最大元素数量是4 294 967 295个。

    /**      * Hash类型      */     private void hashDemo() {         RMap<Object, Object> map = redisUtils.getMap(mapDemo);         map.put(demoId1, 123);         map.put(demoId100, 13000);         Object demoId1Obj = map.get(demoId1);         log.info(Hash 测试数据:{}, demoId1Obj);     } 

集合(Set)

  基于Redisson的分布式Set结构的RSet Java对象实现了java.util.Set接口。通过元素的相互状态比较保证了每个元素的唯一性。该对象的最大容量受Redis限制,最大元素数量是4 294 967 295个。

    /**      * Set 测试      */     private void setDemo() {         RSet<String> set = redisUtils.getSet(setKey);         set.add(value777);         log.info(Set 测试数据);         Iterator<String> iterator = set.iterator();         while (iterator.hasNext()) {             String next = iterator.next();             log.info(next);         }     } 

列表(List)

  基于Redisson分布式列表(List)结构的RList Java对象在实现了java.util.List接口的同时,确保了元素插入时的顺序。该对象的最大容量受Redis限制,最大元素数量是4 294 967 295个。

    /**      * List数据类型      */     private void listDemo() {         RList<String> list = redisUtils.getList(listDemo);         list.add(listValue1);         list.add(listValue2);          log.info(List 测试数据:{}, list.get(1));     } 

综合示例

  将上述各个demo放入一个API中,以便快速测试:

 import lombok.extern.slf4j.Slf4j; import org.redisson.api.*; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController;  import javax.annotation.Resource; import java.util.HashMap; import java.util.Iterator; import java.util.Map;  @Slf4j @RestController @RequestMapping(value = /redisson, method = RequestMethod.POST) public class StudyRedissonController {      @Resource     private RedisUtils redisUtils;      private static String DEMO_STR = demoStr;      @PostMapping(/learnRedisson)     public void learnRedisson() {         //三种数据结构使用示例         strDemo();         hashDemo();         listDemo();         setDemo();         getKeys();     }      private void getKeys() {         RKeys keys = redisUtils.getKeys();         Iterable<String> allKeys = keys.getKeys();         StringBuilder sb = new StringBuilder();         for (String key : allKeys) {             sb = sb.append(key).append(,);         }         log.info(所有的key:{}, sb.substring(0, sb.length() - 1));         // 模糊查询以 map 打头的所有 key         allKeys = keys.getKeysByPattern(map*);         sb = new StringBuilder();         for (String key : allKeys) {             sb = sb.append(key).append(,);         }         log.info(模糊匹配到的key:{}, sb.substring(0, sb.length() - 1));     }     /**      * Hash类型      */     private void hashDemo() {         RMap<Object, Object> map = redisUtils.getMap(mapDemo);         map.put(demoId1, 123);         map.put(demoId100, 13000);         Object demoId1Obj = map.get(demoId1);         log.info(Hash 测试数据:{}, demoId1Obj);     }      /**      * String 数据类型      */     private void strDemo() {         redisUtils.setStr(DEMO_STR, Hello, String.);         log.info(String 测试数据:{}, redisUtils.getStr(DEMO_STR));         redisUtils.setStr(myBucket, myBucketIsXxx);         RBuckets buckets = redisUtils.getBuckets();         Map<String, String> foundBuckets = buckets.get(myBucket*);         Map<String, Object> map = new HashMap<>();         map.put(myBucket1, value1);         map.put(myBucket2, 30L);          // 同时保存全部通用对象桶。         buckets.set(map);         Map<String, String> loadedBuckets = buckets.get(myBucket1, myBucket2, myBucket3);         log.info(跨桶String 测试数据:{}, loadedBuckets);         map.put(myBucket3, 320L);     }      /**      * List数据类型      */     private void listDemo() {         RList<String> list = redisUtils.getList(listDemo);         list.add(listValue1);         list.add(listValue2);          log.info(List 测试数据:{}, list.get(1));     }     /**      * Set 测试      */     private void setDemo() {         RSet<String> set = redisUtils.getSet(setKey);         set.add(value777);         log.info(Set 测试数据);         Iterator<String> iterator = set.iterator();         while (iterator.hasNext()) {             String next = iterator.next();             log.info(next);         }     }  } 

  启动服务,调用如上API,则控制台打印的执行结果如下:


操作redis的执行结果

结束语

  本文中,Wiener介绍了基于Redisson的redis基础操作,包括对象桶、集合、列表和哈希表。大家对于这件事都是怎么看的呢?欢迎在文章下方留言讨论,三人行必有我师焉!小编会仔仔细细地看每条留言。

Reference