Spring Boot 整合Redisson操作Redis基础篇

  1. Spring Boot 整合Redisson配置篇
  2. Spring Boot 整合Redisson操作Redis基础篇
  3. Redisson批量操作类RBuckets和管道利器RBatch

摘要:介绍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

posted @ 2022-05-10 20:51  楼兰胡杨  阅读(5390)  评论(0编辑  收藏  举报