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基础操作,包括对象桶、集合、列表和哈希表。大家对于这件事都是怎么看的呢?欢迎在文章下方留言讨论,三人行必有我师焉!小编会仔仔细细地看每条留言。