Redisson批量操作類RBuckets和管道利器RBatch

樓蘭胡楊發表於2022-05-14
  1. Spring Boot 整合Redisson配置篇
  2. Spring Boot 整合Redisson操作Redis基礎篇
  3. 《Redisson批量操作類RBuckets和管道利器RBatch》

摘要:使用Redisson的類RBuckets和RBatch批量操作Redis,減少網路請求次數。

綜述

  Redis的部署方式有單節點部署、哨兵方式部署、叢集方式部署3種方式,這3中方式都使用的是原生的redis。本文基於單節點部署,使用的Spring Boot版本為2.5.x

RBuckets批量操作

  在Spring Boot專案中,通過RBuckets介面實現批量操作多個RBucket物件,官方示例如下:

RBuckets buckets = redisson.getBuckets();
Map<String, V> loadedBuckets = buckets.get("myBucket1", "myBucket2", "myBucket3");
Map<String, Object> map = new HashMap<>();
map.put("myBucket1", new MyObject());
map.put("myBucket2", new MyObject());
// 利用Redis的事務特性,同時儲存所有的通用物件桶,如果任意一個通用物件桶已經存在則放棄儲存其他所有資料。
buckets.trySet(map);
// 同時儲存全部通用物件桶。
buckets.set(map);

  方法介紹:

  • Map<String,V> get(String... keys):返回桶的key-value對。
  • boolean trySet(Map<String,?> buckets):利用Redis的事務特性,同時儲存所有的通用物件桶,如果任意一個通用物件桶已經存在則放棄儲存其他所有資料。
  • void set(Map<String,?> buckets):同時儲存全部通用物件桶。

RBatch 批量操作

  多個連續命令可以通過RBatch物件在一次網路會話請求裡合併傳送,這樣省去了產生多個請求消耗的時間和資源。這在Redis中叫做管道。

  RBatch管道功能就是REDIS的批量傳送,實際上是客戶端的功能,與服務端無關。相當於把多個請求的命令放在一個資料包通過TCP傳送到服務端,然後客戶端再一次性讀取所有的命令回應。管道技術最顯著的優勢是提高了 redis 服務的效能。

   /**
     * 批量操作
     */
    private void batchDemo() throws ExecutionException, InterruptedException {
        Map<String, String> map = new HashMap<>();
        map.put("abc", "testStr");
        map.put("abcDemo", "redis");
        redisUtils.setMassStrings(map);

        log.info("String 測試資料:{}", redisUtils.getStr("abc") + " "
                + redisUtils.getStr("abcDemo"));

        RBatch batch = redisUtils.createBatch();
        // 模擬購物車場景,真實場景中請替換店鋪ID shopId 和商品ID commodityId
        String field = "shopId:commodityId";
        // 把即將執⾏的命令放進 RBatch
        RMapAsync testMap = batch.getMap("customerId:"+ 32L);
        // 更新value,並返回上一次的值
        String commodityNum = "mapValue" + String.valueOf((int)(Math.random()*9 + 100));
        log.info("當前商品數量commodityNum是:{}", commodityNum);
        testMap.putAsync(field, commodityNum);
        testMap.putAsync("test2", "mapValue3");
        testMap.putAsync("test2", "mapValue5");
        testMap.putAsync("test:"+ String.valueOf((int)(Math.random()*900 + 100)), String.valueOf((int)(Math.random()*900 + 100)));

        RAtomicLongAsync counter = batch.getAtomicLong("counter");

        RFuture<Long> num = counter.incrementAndGetAsync();

        // 執行RBatch中的全部命令,並返回執行結果
        BatchResult result = batch.execute();
        List list = result.getResponses();
        log.info("Map Batch 執行結果:{}", list);
        log.info("計數器當前值:{}", num.get());
    }

  執行batchDemo()後,控制檯列印結果如下:

StudyRedissonController - String 測試資料:testStr redis
StudyRedissonController - 當前商品數量commodityNum是:mapValue106
StudyRedissonController - Map Batch 執行結果:[mapValue101, mapValue5, mapValue3, null, 8]
StudyRedissonController - 計數器當前值:8

  測試用例主要介紹了Hash,順便介紹一下它的使用場景:

  • 儲存結構化的資料,比如 Java 中的物件。其實 Java 中的物件也可以用 string 進行儲存,只需要將物件序列化成 json 字串就可以,但是如果這個物件的某個屬性更新比較頻繁的話,那麼每次就需要重新將整個物件序列化儲存,這樣消耗開銷比較大。可如果用 hash 來儲存物件的每個屬性,那麼每次只需要更新要更新的屬性就可以。
  • 購物車場景。以業務線+使用者id作為key,以店鋪編號+商品的id作為儲存的field,以選購商品數量作為鍵值對的value,這樣就構成了購物車的三個要素。

  在叢集模式下,所有的命令會按各個槽所在的節點,篩選分配到各個節點並同時傳送。每個節點返回的結果將會彙總到最終的結果列表裡。上述demo中用到的工具類如下:

@Component
public class RedisUtils {

    private RedisUtils() {
    }

    /**
     * 預設快取時間
     */
    private static final Long DEFAULT_EXPIRED = 32000L;

    /**
     * 自動裝配redisson client物件
     */
    @Resource
    private RedissonClient redissonClient;
    /**
     * 獲取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();
    }

   // ---------------- 批量操作 ------------------------
    /**
     * 獲取RBatch
     *
     * @return RBatch
     */
    public RBatch createBatch() {
        return redissonClient.createBatch();
    }

    /**
     * 批量移除快取
     *
     * @param keys key 物件
     */
    public void deleteBatch(String... keys) {
        if (null == keys) {
            return;
        }
        this.getKeys().delete(keys);
    }

    /**
     * 批量快取字串,缺點:不可以設定過期時間
     *
     * @param map 快取key-value
     */
    public void setMassStrings(Map<String, String> map) {
        if (MapUtils.isEmpty(map)) {
            return;
        }
        RBuckets buckets = redissonClient.getBuckets();
        // 同時儲存全部通用物件桶。
        buckets.set(map);
    }

    /**
     * 批量快取字串,支援過期
     *
     * @param map 快取key-value
     * @param leaseTime 快取有效期,必傳
     */
    public void setMassStrings(Map<String, String> map, long leaseTime) {
        if (MapUtils.isEmpty(map)) {
            return;
        }
        final long expireTime = leaseTime <= 0L ? DEFAULT_EXPIRED : leaseTime;
        RBatch batch = redissonClient.createBatch();
        map.forEach(new BiConsumer<String, String>() {
            public void accept(String key, String value) {
                batch.getBucket(key).setAsync(value, expireTime, TimeUnit.SECONDS);
            }
        });
        batch.execute();
    }

}

結束語

  關於redisson中如何使用批量操作類RBuckets和管道利器RBatch就分享到這裡,希望本文對大家的學習或者工作具有一定的參考和學習價值;如果有疑問,大家可以在評論區留言交流,也希望大家多多點贊關注。謝謝大家對樓蘭胡楊的支援!

Reference

相關文章