之前利用springBoot中的緩存機制,使用Redis作為緩存容器唉锌,做了一個緩存的簡單Demo,當(dāng)然Redis不僅僅可以用來做緩存的容器,還有很多開發(fā)的實際場景中會用到Redis的特性眉踱,通過幾天的學(xué)習(xí),現(xiàn)將學(xué)習(xí)的成果整理分享給大家霜威。希望大家也多多討論谈喳,提供跟多的使用場景,來熟練掌握在springboot中的使用戈泼。
此項目下載地址:https://git.oschina.net/z77z/springboot_mybatisplus
Redis的特性
-
Strings:Strings 數(shù)據(jù)結(jié)構(gòu)是簡單的key-value類型婿禽,value其實不僅是String,也可以是數(shù)字.
常用命令: set,get,decr,incr,mget 等大猛。
常用方法:
- 獲取字符串長度
- 往字符串a(chǎn)ppend內(nèi)容
- 設(shè)置和獲取字符串的某一段內(nèi)容
- 設(shè)置及獲取字符串的某一位(bit)
- 批量設(shè)置一系列字符串的內(nèi)容
Hashs:Redis Hash對應(yīng)Value內(nèi)部實際就是一個HashMap扭倾,常用命令:hget,hset,hgetall 等。
Lists:Redis list的實現(xiàn)為一個雙向鏈表挽绩,即可以支持反向查找和遍歷膛壹,更方便操作,不過帶來了部分額外的內(nèi)存開銷,Redis內(nèi)部的很多實現(xiàn)模聋,包括發(fā)送緩沖隊列等也都是用的這個數(shù)據(jù)結(jié)構(gòu)肩民。
常用命令:lpush,rpush,lpop,rpop,lrange等。Sets:Sets 集合的概念就是一堆不重復(fù)值的組合撬槽。Redis還為集合提供了求交集此改、并集、差集等操作侄柔,可以非常方便的實現(xiàn)如共同關(guān)注共啃、共同喜好、二度好友等功能暂题。
常用命令:sadd,spop,smembers,sunion 等移剪。Sorted Sets:Redis sorted set的使用場景與set類似,區(qū)別是set不是自動有序的薪者。sorted set可以通過用戶額外提供一個優(yōu)先級(score)的參數(shù)來為成員排序纵苛,并且是插入有序的,即自動排序言津。
常用命令:zadd,zrange,zrem,zcard等
下面就根據(jù)這幾個特性攻人,也就是Redis支持的數(shù)據(jù)類型,來完成以下場景的實現(xiàn)悬槽。
場景一:簡單計數(shù)功能
Redis是一個很好的計數(shù)器怀吻,計數(shù)器是 Redis 的原子性自增操作可實現(xiàn)的最直觀的模式了,它的想法相當(dāng)簡單:每當(dāng)某個操作發(fā)生時初婆,向 Redis 發(fā)送一個 INCR 命令蓬坡。使用場景比如網(wǎng)站的訪問數(shù),注冊用戶數(shù)磅叛,文章的點贊數(shù)屑咳,高并發(fā)的秒殺活動,分布式序列號生成等等統(tǒng)計計數(shù)的功能實現(xiàn)弊琴。Redis 解決這類計數(shù)問題得心應(yīng)手兆龙,相比關(guān)系數(shù)據(jù)庫速度更快,消耗資源更少敲董。還可以通過set()方法來重置計數(shù)紫皇。
// 簡單計數(shù)
@Test
public void test1() {
try {
ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
//計數(shù)前打印
System.out.println(opsForValue.get("test1"));
for (int i = 0; i < 100; i++) {
//計數(shù),第一個參數(shù)為key值臣缀,第二個參數(shù)為每次增加計數(shù)的單位
opsForValue.increment("test1", 1);
}
//計數(shù)后打印
System.out.println(opsForValue.get("test1"));
} catch (Exception e) {
e.printStackTrace();
}
}
場景二:按時間統(tǒng)計計數(shù)
有時候除了簡單的計數(shù)外,比如注冊用戶數(shù)需要按日統(tǒng)計泻帮,處理方法比較簡單精置,把日期帶入計數(shù)器 key 就可以。以此類推锣杂,還可以按其他方式進(jìn)行統(tǒng)計計數(shù)脂倦,只需要把統(tǒng)計的方式添加到key值就可以了
// 按時間計數(shù)
@Test
public void test2() {
//將日期添加到key值中
String key = "test2_" + new SimpleDateFormat("yyyy-MM-dd").format(new Date());
try {
ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
System.out.println(opsForValue.get(key));
for (int i = 0; i < 100; i++) {
opsForValue.increment(key, 1);
}
System.out.println(opsForValue.get(key));
} catch (Exception e) {
e.printStackTrace();
}
}
場景三:按模糊Key值查詢
在按條件統(tǒng)計計數(shù)的時候番宁,把時間加入到了key值中,有時候要只是查詢某個對象的統(tǒng)計數(shù)時赖阻,就可以使用模糊Key值查詢蝶押。
// 模糊K值查詢
@Test
public void test3() {
try {
ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
//先獲取前綴為test的Key值列表。
Set<String> keys = stringRedisTemplate.keys("test*");
//遍歷滿足條件的Key值獲取對應(yīng)的value值
for (String a : keys) {
System.out.println(a + ":" + opsForValue.get(a));
}
} catch (Exception e) {
e.printStackTrace();
}
}
場景四:設(shè)置Key的有效時間(防止高并發(fā)訪問)
在redis中可以設(shè)置key值的有效時間火欧,用戶訪問鏈接的時候棋电,將用戶的唯一信息比如ip地址等為key值,時間為value值苇侵,在redis中記錄一下赶盔,在用戶再次訪問的時候,通過key值獲取前一次訪問的時間榆浓,比較時間的間隔于未,如果低于閥值,就拒絕這次請求陡鹃,防止用戶多次訪問烘浦。這里只是寫下在spring的RedisTemplate接口怎么使用。具體的邏輯實現(xiàn)自己搞定萍鲸。
// 設(shè)置key值的有效時間
@Test
public void test4() {
try {
ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
opsForValue.set("test4", "test4");
System.out.println(opsForValue.get("test4"));
// TimeUnit.SECONDS:解釋定時參數(shù)的單位
// MICROSECONDS 微秒 一百萬分之一秒(就是毫秒/1000)
// MILLISECONDS 毫秒 千分之一秒
// NANOSECONDS 毫微秒 十億分之一秒(就是微秒/1000)
// SECONDS 秒
// MINUTES 分鐘
// HOURS 小時
// DAYS 天
if(stringRedisTemplate.expire("test4", 5, TimeUnit.SECONDS)){
System.out.println("設(shè)置過期時間成功,等待闷叉。。猿推。片习。");
Thread.sleep(5001);
}
System.out.println(opsForValue.get("test4"));
} catch (Exception e) {
e.printStackTrace();
}
}
場景五:使用hashs存儲獲取修改java對象
在實際開發(fā)中,我們經(jīng)常將一些結(jié)構(gòu)化的信息打包成HashMap蹬叭,在客戶端序列化后存儲為一個字符串的值藕咏,比如用戶的昵稱、年齡秽五、性別孽查、積分等,這時候在需要修改其中某一項時坦喘,通常需要將所有值取出反序列化后盲再,修改某一項的值,再序列化存儲回去瓣铣。這樣不僅增大了開銷答朋,也不適用于一些可能并發(fā)操作的場合(比如兩個并發(fā)的操作都需要修改積分)。
而Redis的Hash結(jié)構(gòu)可以使你像在數(shù)據(jù)庫中Update一個屬性一樣只修改某一項屬性值棠笑。因為Redis的Hash結(jié)構(gòu)是以對象的名字作為redis的key值梦碗,以對象的唯一屬性值作為hash的key值,以對象來作為redis的value值。結(jié)構(gòu)圖如下:
// 使用hashs存儲獲取對象
@Test
public void test5(){
BeautifulPictures beautifulPictures = beautifulPicturesService.selectById(1);
HashOperations<String, Object, BeautifulPictures> hash = redisTemplate.opsForHash();
hash.put("test5",beautifulPictures.getId(),beautifulPictures);
System.out.println(hash.get("test5", beautifulPictures.getId()));
}
場景六:使用lists有序存儲讀取
適用于獲取最近N個操作的數(shù)據(jù)洪规。
//使用lists存儲讀取 有序
@Test
public void test6(){
ListOperations<String, String> list = stringRedisTemplate.opsForList();
list.leftPush("test6", "1");
list.leftPush("test6", "2");
list.leftPush("test6", "3");
list.leftPush("test6", "4");
list.leftPush("test6", "5");
list.leftPush("test6", "6");
list.leftPush("test6", "7");
//保持鏈表只有3位
list.trim("test6", 0, 2);
System.out.println(list.range("test6", 0, list.size("test6")-1));
}
場景七:使用sets存儲讀取 無序 去重 求差集印屁,交集,并集
//使用set存儲讀取 無序 去重 求差集斩例,交集,并集
@Test
public void test7(){
SetOperations<String, String> set = stringRedisTemplate.opsForSet();
set.add("test7_1", "2", "1","2","3","4","4","3");
set.add("test7_2", "2", "6","2","3","7","6","5");
System.out.println("全部成員"+set.members("test7_1"));
System.out.println("差集"+set.difference("test7_1", "test7_2"));
System.out.println("交集"+set.intersect("test7_1", "test7_2"));
System.out.println("并集"+set.union("test7_1", "test7_2"));
}
場景八:Sorted Set 存取數(shù)據(jù) 排序
//Sorted Set 存取數(shù)據(jù) 排序 相比sets 保存時多一個權(quán)重參數(shù)score念赶,相當(dāng)于按照此參數(shù)來排序
@Test
public void test8(){
ZSetOperations<String, String> zSet = stringRedisTemplate.opsForZSet();
zSet.add("test8", "use1", 9);
zSet.add("test8", "use2", 1);
zSet.add("test8", "use3", 5);
zSet.add("test8", "use4", 9);
//對應(yīng)的score值增加
//zSet.incrementScore("test8", "use1", 1);
System.out.println(zSet.reverseRange("test8", 0, zSet.size("test8")-1));
}