Redisson操作Redis数据类型全攻略:从“键值小白”到“数据结构大师”

256 阅读4分钟

一、字符串(String)

核心类RBucketRAtomicLong

1. 基础操作

RBucket<String> bucket = redisson.getBucket("user:1:name");  
bucket.set("码哥"); // 设置值  
String name = bucket.get(); // 获取值  
bucket.compareAndSet("码哥", "Bug终结者"); // 原子替换  
bucket.delete(); // 删除键  

2. 原子计数器

RAtomicLong counter = redisson.getAtomicLong("article:views:123");  
counter.incrementAndGet(); // 自增1  
counter.addAndGet(10); // 增加10  

最佳实践

  • RAtomicLong替代INCR命令,避免并发问题。
  • 频繁更新的计数器可开启writeBehind模式批量持久化。

二、哈希(Hash)

核心类RMap

1. 对象存储

RMap<String, Object> userMap = redisson.getMap("user:1");  
userMap.put("name", "张三");  
userMap.put("age", 30);  
userMap.expire(1, TimeUnit.HOURS); // 设置过期时间  

// 批量操作  
Map<String, Object> data = new HashMap<>();  
data.put("email", "zhangsan@example.com");  
data.put("city", "北京");  
userMap.putAll(data);  

// 获取所有字段  
Map<String, Object> allFields = userMap.readAllMap();  

2. 原子操作

userMap.computeIfPresent("age", (k, v) -> (Integer)v + 1); // 原子递增年龄  

避坑指南

  • 大哈希使用RMapCache支持本地缓存,减少网络开销。
  • 避免频繁遍历整个哈希,优先用getAll()readAllMap()

三、列表(List)

核心类RList

1. 队列操作

RList<String> taskQueue = redisson.getList("task:queue");  
taskQueue.add("任务A"); // 右侧插入  
taskQueue.addFirst("紧急任务"); // 左侧插入  
String task = taskQueue.remove(0); // 移除并获取第一个元素  

// 分页查询  
List<String> page = taskQueue.range(10, 20); // 获取第10到20个元素  

2. 阻塞队列

RBlockingQueue<String> bq = redisson.getBlockingQueue("msg:queue");  
bq.put("消息内容"); // 生产者插入  
String msg = bq.take(); // 消费者阻塞获取  

适用场景

  • 消息队列、最新N条记录(配合trim()方法)。

四、集合(Set)

核心类RSet

1. 去重集合

RSet<String> ipSet = redisson.getSet("active:ips");  
ipSet.add("192.168.1.1");  
boolean exists = ipSet.contains("192.168.1.1");  

// 集合运算  
RSet<String> todaySet = redisson.getSet("ips:20231001");  
RSet<String> yesterdaySet = redisson.getSet("ips:20230930");  
Set<String> repeatIps = todaySet.intersection(yesterdaySet); // 求交集  

性能优化

  • 大数据集使用RSetCache自动淘汰冷数据。

五、有序集合(Sorted Set)

核心类RScoredSortedSet

1. 排行榜实现

RScoredSortedSet<String> rank = redisson.getScoredSortedSet("game:rank");  
rank.add(1000, "玩家A"); // 分数为1000  
rank.add(1500, "玩家B");  

// 获取TOP3  
Collection<String> top3 = rank.valueRangeReversed(0, 2);  
// 查询玩家排名(从0开始)  
int position = rank.rank("玩家B"); // 返回升序排名  
int reversedRank = rank.revRank("玩家B"); // 返回降序排名  

2. 范围查询

// 获取分数在[800, 1200]的玩家  
Collection<String> players = rank.valueRange(800, true, 1200, true);  

技巧

  • 使用addAndGetRank()方法同时添加元素并获取排名。

六、地理空间(Geospatial)

核心类RGeo

1. 存储与查询地理位置

RGeo<String> geo = redisson.getGeo("delivery:points");  
geo.add(116.405285, 39.904989, "北京站");  
geo.add(121.473701, 31.230416, "上海站");  

// 查找北京站附近200km内的站点  
List<GeoEntry> nearby = geo.radius(116.405285, 39.904989, 200, GeoUnit.KILOMETERS);  

七、位图(Bitmap)

核心类RBitSet

1. 用户签到统计

RBitSet signIn = redisson.getBitSet("user:1:signin:202310");  
signIn.set(5); // 第5天签到(offset从0开始)  
boolean isSigned = signIn.get(5);  

// 统计本月签到天数  
int count = signIn.cardinality();  

优化建议

  • 按周/月拆分键,避免单个位图过大。

八、HyperLogLog

核心类RHyperLogLog

1. UV统计

RHyperLogLog<String> uv = redisson.getHyperLogLog("uv:20231001");  
uv.add("192.168.1.1");  
uv.add("192.168.1.2");  
long count = uv.count(); // 获取近似独立访客数  

// 合并多日数据  
RHyperLogLog<String> totalUv = redisson.getHyperLogLog("uv:total");  
totalUv.mergeWith("uv:20231001", "uv:20231002");  

注意

  • HyperLogLog 误差率约0.81%,适合大数据量去重统计。

九、流(Stream)

核心类RStream

1. 消息流处理

RStream<String, String> stream = redisson.getStream("logs");  
// 添加消息  
String id = stream.add(StreamMessageId.NEW_ENTRY, Map.of("level", "ERROR", "msg", "DB连接失败"));  

// 消费者组读取  
StreamMessageId lastId = ...;  
Map<StreamMessageId, Map<String, String>> messages = stream.readGroup("consumer-group", "consumer1", lastId, 10);  

十、最佳实践总结

  1. 选择合适的数据结构

    • 统计UV → RHyperLogLog
    • 排行榜 → RScoredSortedSet
    • 消息队列 → RBlockingQueueRStream
  2. 性能优化

    • 批量操作:优先使用addAll()putAll()等方法减少网络开销。
    • 本地缓存:对读多写少的数据启用RMapCacheRSetCache
  3. 资源管理

    • 及时释放连接:使用try-with-resources包裹需要关闭的对象。
    • 设置合理TTL:通过expire()避免数据无限增长。
  4. 事务与原子性

    • 复杂操作使用RBatch批量执行:
      RBatch batch = redisson.createBatch();  
      batch.getMap("user:1").fastPutAsync("name", "李四");  
      batch.getAtomicLong("counter").incrementAndGetAsync();  
      batch.execute();  
      

最后忠告

  • 像使用java.util包一样自然,但时刻记住数据在远程——网络延迟和分区容忍才是真正的Boss