likes
comments
collection
share

基于Redission高级应用19-RMultimap原理及高级工具类封装解读

作者站长头像
站长
· 阅读数 31

RMultimap 是 Redisson 实现的一种分布式数据结构,它类似于 Java 中的 Multimap。在 Multimap 中,一个键可以映射到多个值,即一个键关联一个值的集合。 这与普通的 Map 结构不同,后者一个键只能映射到单个值。

原理

RMultimap 的工作原理基于 Redis 的数据结构,主要有两种类型:

  1. RSetMultimap: 这种类型的 RMultimap 使用 Redis 的 HashSet 数据结构。Hash 用于存储键,而每个键对应的 Set 存储多个值。这样,你可以将多个值与同一个键关联起来。

  2. RListMultimap: 类似于 RSetMultimap,但是每个键对应的是一个 List 而不是 Set。这允许值有序地存储,并且可以有重复的值。

无论是 RSetMultimap 还是 RListMultimap,它们都提供了类似的 API 来操作多值映射,如添加、删除键值对,获取与键关联的所有值等。

类图:

implements
implements
creates
uses
«interface»
RMultimap
+put(K key, V value) : boolean
+get(K key) : Collection<V>
+remove(K key, V value) : boolean
+removeAll(K key) : Collection<V>
RSetMultimap
+put(K key, V value) : boolean
+get(K key) : Collection<V>
+remove(K key, V value) : boolean
+removeAll(K key) : Collection<V>
RListMultimap
+put(K key, V value) : boolean
+get(K key) : Collection<V>
+remove(K key, V value) : boolean
+removeAll(K key) : Collection<V>
RedissonClient
+getSetMultimap(String name) : RSetMultimap
+getListMultimap(String name) : RListMultimap
MultimapUtils
-redissonClient RedissonClient
+put(String mapName, String key, String value) : boolean
+getAll(String mapName, String key) : Collection<String>
+remove(String mapName, String key, String value) : boolean
+removeKey(String mapName, String key) : boolean
+shutdown() : void

在类图中:

  • RMultimap 是一个接口,定义了多值映射的基本操作。
  • RSetMultimapRListMultimapRMultimap 的两个具体实现,分别代表使用 Redis 的 SetList 数据结构。
  • RedissonClient 是一个类,提供了方法来创建和操作 RSetMultimapRListMultimap
  • MultimapUtils 是一个工具类,它封装了 RedissonClient 的操作,提供了更简单的 API,并管理 RedissonClient 的生命周期。

优点

  1. 数据结构丰富: 提供了更丰富的数据结构,允许一个键关联多个值。

  2. 分布式环境: 适用于分布式环境,可以在多个应用实例之间共享和操作多值映射。

  3. 高可用性和可伸缩性: 由于基于 Redis,可以从 Redis 的高可用性和可伸缩性中获益。

  4. 操作灵活: 提供了灵活的操作,可以轻松地添加、删除和获取键值对。

  5. 有序和无序: 可以选择有序(RListMultimap)或无序(RSetMultimap)的值集合,根据实际需求灵活选择。

缺点

  1. 内存限制: 由于 Redis 主要是基于内存的存储,大量的键值对可能会消耗大量内存。

  2. 性能开销: 对于 RListMultimap,列表操作可能会随着列表长度的增长而变慢,特别是对于列表中间的插入和删除操作。

  3. 网络延迟: 在分布式环境中,所有操作都需要通过网络进行,可能会受到网络延迟的影响。

  4. 数据一致性: 在高并发环境中,需要仔细设计以保证数据的一致性和原子性。

  5. 成本: 如果存储的数据量非常大,可能需要更多的 Redis 资源,从而增加成本。

使用场景:1. 索引: RMultimap 可用于构建索引,例如,在全文搜索中,可以将单词映射到包含该单词的文档ID集合。

  1. 反向索引: 在数据库中,可以使用 RMultimap 来存储反向索引,将特定的值映射到具有该值的所有键。

  2. 社交网络: 在社交网络应用中,可以使用 RMultimap 来存储用户和他们的朋友列表或关注者列表。

  3. 分组: 对于需要对数据进行分组的应用,比如将用户按国家或兴趣分组,RMultimap 可以有效地管理这种一对多的关系。

  4. 标签系统: RMultimap 可以用于实现标签系统,将标签映射到拥有该标签的所有项目。

  5. 多值字典: 在需要存储多个翻译或定义的字典应用中,可以使用 RMultimap 来存储每个词条的多个翻译。

  6. 权限管理: 在权限管理系统中,可以使用 RMultimap 来存储用户和他们的权限列表,或者角色和角色所拥有的权限列表。

  7. 任务分配: 在工作流或任务分配系统中,RMultimap 可以用来追踪哪些任务分配给了哪些工作人员。

  8. 数据分类: 在需要对数据进行分类的任何场景中,RMultimap 都可以提供一种方便的方式来将数据分类到不同的集合中。

  9. 缓存关联数据: 在缓存解决方案中,可以使用 RMultimap 来存储与特定对象相关联的数据,如用户ID和其缓存的查询结果。

RMultimap 适合于需要将多个值与一个键关联的场景,例如社交网络中的用户和朋友列表、索引、分类数据等。选择 RMultimap 还是其他数据结构需要根据具体的应用场景和需求来决定。

简单使用:

### import org.redisson.Redisson;
import org.redisson.api.RListMultimap;
import org.redisson.api.RSetMultimap;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

import java.util.Collection;
/**
 * @Author derek_smart
 * @Date 202/5/22 9:38
 * @Description RMultimap 简单使用
 * <p>
 * RMultimap 简单使用
 */
public class RedissonMultimapExample {

    public static void main(String[] args) {
        // 配置 Redisson 客户端
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        RedissonClient redisson = Redisson.create(config);

        // 使用 RSetMultimap
        RSetMultimap<String, String> setMultimap = redisson.getSetMultimap("derekSetMultimap");
        setMultimap.put("fruits", "apple");
        setMultimap.put("fruits", "banana");
        setMultimap.put("fruits", "orange");

        // 获取并打印所有 "fruits" 键下的值
        Collection<String> allFruits = setMultimap.getAll("fruits");
        System.out.println("All fruits: " + allFruits);

        // 使用 RListMultimap
        RListMultimap<String, String> listMultimap = redisson.getListMultimap("derekListMultimap");
        listMultimap.put("colors", "red");
        listMultimap.put("colors", "green");
        listMultimap.put("colors", "blue");
        listMultimap.put("colors", "red"); // 可以添加重复的值

        // 获取并打印所有 "colors" 键下的值
        Collection<String> allColors = listMultimap.getAll("colors");
        System.out.println("All colors: " + allColors);
        // 关闭 Redisson 客户端
        redisson.shutdown();
    }
}

基于Redission高级应用19-RMultimap原理及高级工具类封装解读

使用要点

  1. 数据类型选择:

    • RSetMultimap: 用于存储唯一的值集合,不允许重复。
    • RListMultimap: 允许重复的值,并保持插入顺序。
  2. 线程安全: Redisson 提供的 RMultimap 是线程安全的,适用于多线程环境。

  3. 分布式特性: 由于基于 Redis,RMultimap 可以在多个应用实例和多个节点之间共享。

  4. 性能考量:

    • RSetMultimap 的性能在大部分情况下与键关联的集合大小无关。
    • RListMultimap 的性能可能随着列表的增长而下降,尤其是在列表中间进行插入或删除操作时。
  5. 资源管理: 在使用完 RMultimap 后,应该适当关闭 Redisson 客户端以释放资源。

RMultimap 工具类

import org.redisson.Redisson;
import org.redisson.api.*;
import org.redisson.config.Config;

import java.util.Collection;
/**
 * @Author derek_smart
 * @Date 202/5/22 9:50
 * @Description RMultimap 工具类
 * <p>
 * RMultimap 工具类
 */
public class MultimapUtils {

    private final RedissonClient redissonClient;

    public MultimapUtils(String redisUrl) {
        Config config = new Config();
        config.useSingleServer().setAddress(redisUrl);
        this.redissonClient = Redisson.create(config);
    }

    public boolean put(String mapName, String key, String value, MultimapType type) {
        RMultimap<String, String> multimap = getMultimap(mapName, type);
        try {
            return multimap.put(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public Collection<String> getAll(String mapName, String key, MultimapType type) {
        RMultimap<String, String> multimap = getMultimap(mapName, type);
        try {
            return multimap.getAll(key);
        } catch (Exception e) {
            e.printStackTrace();   return null;
        }
    }

    public boolean remove(String mapName, String key, String value, MultimapType type) {
        RMultimap<String, String> multimap = getMultimap(mapName, type);
        try {
            return multimap.remove(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean removeKey(String mapName, String key, MultimapType type) {
        RMultimap<String, String> multimap = getMultimap(mapName, type);
        try {
            return multimap.removeAll(key).size() > 0;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private RMultimap<String, String> getMultimap(String mapName, MultimapType type) {
        switch (type) {
            case SET:
                return redissonClient.getSetMultimap(mapName);
            case LIST:
                return redissonClient.getListMultimap(mapName);
            default:
                throw new IllegalArgumentException("Unsupported multimap type: " + type);
        }
    }

    public void shutdown() {
        redissonClient.shutdown();
    }

    public enum MultimapType {
        SET,
        LIST
    }
}

基于Redission高级应用19-RMultimap原理及高级工具类封装解读

ClientMultimapUtilsRedissonClientRSetMultimapRListMultimapput("mySetMultimap", "key1", "value1", MultimapType.SET)getSetMultimap("mySetMultimap")createInstance()return RSetMultimapput("key1", "value1")return truereturn truegetAll("mySetMultimap", "key1", MultimapType.SET)getSetMultimap("mySetMultimap")createInstance()return RSetMultimapgetAll("key1")return Collection of valuesreturn Collection of valuesput("myListMultimap", "key1", "value1", MultimapType.LIST)getListMultimap("myListMultimap")createInstance()return RListMultimapput("key1", "value1")return truereturn truegetAll("myListMultimap", "key1", MultimapType.LIST)getListMultimap("myListMultimap")createInstance()return RListMultimapgetAll("key1")return Collection of values (including duplicates)return Collection of values (including duplicates)remove("mySetMultimap", "key1", "value1", MultimapType.SET)getSetMultimap("mySetMultimap")createInstance()return RSetMultimapremove("key1", "value1")return truereturn trueremoveKey("myListMultimap", "key1", MultimapType.LIST)getListMultimap("myListMultimap")createInstance()return RListMultimapremoveAll("key1")return true (if any values were associated with the key)return true (if any values were associated with the key)shutdown()shutdown()returnreturnClientMultimapUtilsRedissonClientRSetMultimapRListMultimap

总结

  • RMultimap 提供了一种方便的方式来处理一对多的关系,适用于需要将多个值与单个键关联的场景。
  • 它结合了 Redis 的高性能和高可用性,非常适合分布式系统和微服务架构。
  • 在选择 RSetMultimapRListMultimap 时,需要根据是否需要值的唯一性和顺序来决定。
  • RMultimap 的操作是原子的,这有助于在分布式环境中维护数据的一致性。
  • 使用 RMultimap 时,需要考虑内存消耗和网络延迟,尤其是在处理大量数据时。
  • 为了提高鲁棒性,可以封装工具类来管理 RMultimap 的操作,并处理可能出现的异常和错误。
  • 对于高并发场景,除了利用 Redisson 的线程安全特性外,还可以考虑使用分布式锁或事务来保证操作的原子性。

总的来说,RMultimap 是 Redisson 提供的一个强大的数据结构,它可以在多种场景下发挥作用,特别是在需要分布式多值映射的应用中。正确使用和管理 RMultimap 可以帮助你构建高效、可扩展的应用程序。

转载自:https://juejin.cn/post/7372871883337449535
评论
请登录