摘要:介绍Redisson中分布式对象和集合的基础操作,包括对象桶、集合、列表和散列。
测试环境为:Spring Boot版本 2.5.x 和 Redisson 单机。关于如何中Spring Boot项目集成Redisson,请戳《Spring Boot 整合Redisson配置篇》。
RedissonClient是线程安全的,由于其内部是通过Netty通信,所以除了同步执行方式,也支持异步执行。
首先提供一个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); } }
每个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 命令实现的,匹配规则示例如下:
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); }
基于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); }
基于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); } }
基于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,则控制台打印的执行结果如下:
本文中,Wiener介绍了基于Redisson的redis基础操作,包括对象桶、集合、列表和哈希表。大家对于这件事都是怎么看的呢?欢迎在文章下方留言讨论,三人行必有我师焉!小编会仔仔细细地看每条留言。