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基礎操作,包括物件桶、集合、列表和雜湊表。大家對於這件事都是怎麼看的呢?歡迎在文章下方留言討論,三人行必有我師焉!小編會仔仔細細地看每條留言。