redis系列:通過demo學習string命令

NO IMAGE

前言

該文章將通過一個小demo將講述Redis中的string類型命令。demo將以springboot為後臺框架快速開發,iview前端框架進行簡單的頁面設計,為了方便就不使用DB存儲數據了,直接採用Redis作為存儲。

文中不會講述springboot用法及項目搭建部分。直接根據功能方面進行講述,穿插string命令操作說明。

如果需要詳細瞭解該項目的其他部分,請點擊下方項目Github地址

項目Github地址:github.com/rainbowda/l…

案例

demo功能是記錄日誌,整個demo的大致頁面如下

redis系列:通過demo學習string命令

準備工作

首先定義一個key的前綴,已經存儲自增id的key

private static final String MY_LOG_REDIS_KEY_PREFIX = "myLog:";
private static final String MY_LOG_REDIS_ID_KEY = "myLogID";

日誌相關的key將會以myLog:1、myLog:2、myLog:3的形式存儲

redis操作對象

private RedisTemplate redisTemplate;
//string 命令操作對象
private ValueOperations valueOperations;

新增

先來看看gif圖吧

redis系列:通過demo學習string命令

來看看後臺的方法

@RequestMapping(value = "/addMyLog",method = RequestMethod.POST)
public boolean addMyLog(@RequestBody JSONObject myLog){
//獲取自增id
Long myLogId = valueOperations.increment(MY_LOG_REDIS_ID_KEY, 1);
String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
myLog.put("id",myLogId);
myLog.put("createDate", date);
myLog.put("updateDate", date);
//將數據寫到redis中
valueOperations.set(MY_LOG_REDIS_KEY_PREFIX+myLogId, myLog.toString());
return true;
}

從上面代碼可以看出有兩個操作redis的地方

valueOperations.increment(MY_LOG_REDIS_ID_KEY, 1);

valueOperations.set(MY_LOG_REDIS_KEY_PREFIX+myLogId, myLog.toString());

命令介紹

valueOperations.increment其實就相當於Redis中的INCR、INCRBY、INCRBYFLOAT、DECR、DECRBY

INCR

INCR key

對存儲在指定key的數值執行原子的加1操作。沒有對應的key則設置為0,再相加

INCRBY

INCRBY key increment

其實和INCR類似,不同的是這個命令可以指定具體加多少

INCRBYFLOAT

INCRBYFLOAT key increment

也是類似的,不同的是加的數值是浮點數

incrbyfloat incrByFloatKey 5.11
incrbyfloat incrByFloatKey 5.22

執行結果如下

redis系列:通過demo學習string命令

下面是java代碼

@Test
public void incrByFloat() {
System.out.println(jedis.incrByFloat("incrByFloatKey", 5.11));
System.out.println(redisTemplate.opsForValue().increment("incrByFloatKey", 5.22));
}

與INCR相反的命令有DECR和DECRBY,這裡就不做介紹了。


valueOperations.set就是對應Redis的SET命令了,相關聯的還有SETEX、SETNX和PSETEX。需要注意的是set在Redis版本2.6.12 提供了EXPXNXXX參數用於取代SETEX、SETNX和PSETEX,後續版本可能會移除SETEX、SETNX和PSETEX命令。下面是官網的原話

Since the SET command options can replace SETNXSETEXPSETEX, it is possible that in future versions of Redis these three commands will be deprecated and finally removed.

SET

SET key value [expiration EX seconds|PX milliseconds] [NX|XX]

設置鍵key對應value
參數選項

EX seconds – 設置鍵key的過期時間,單位時秒
PX milliseconds – 設置鍵key的過期時間,單位時毫秒
NX – 只有鍵key不存在的時候才會設置key的值
XX – 只有鍵key存在的時候才會設置key的值

SETRANGE

SETRANGE key offset value

替換從指定長度開始的字符

set setRangeKey "Hello World"
setrange setRangeKey 6 "Redis"
get setRangeKey

執行結果如下

redis系列:通過demo學習string命令

下面是java代碼

@Test
public void setRange() {
jedis.set("setRangeKey", "Hello World");
jedis.setrange("setRangeKey", 6 , "Redis");
System.out.println(jedis.get("setRangeKey"));
//spring
redisTemplate.opsForValue().set("setRangeKey", "learyRedis", 6);
System.out.println(redisTemplate.opsForValue().get("setRangeKey"));
}
MSET

MSET key value [key value …]

同時設置多個key、value
###### MSETNX

MSETNX key value [key value …]

同時設置多個key、value,key存在則忽略

查詢

接著寫個查詢方法,將新增的內容查詢出來

@RequestMapping(value = "/getMyLog",method = RequestMethod.GET)
public List getMyLog(){
//獲取mylog的keys
Set myLogKeys = redisTemplate.keys("myLog:*");
return  valueOperations.multiGet(myLogKeys);
}

方法中的兩行都涉及到了Redis操作,先是通過keys命令獲取myLog:*相關的key集合,然後通過multiGet方法(也就是mget命令)獲取記錄。

命令介紹
KEYS

KEYS pattern

查找所有符合給定模式pattern(正則表達式)的 key

GET

GET key

獲取key對應的value

set getKey getValue
get getKey

執行結果如下

redis系列:通過demo學習string命令

GETRANGE

GETRANGE key start end

獲取start到end之間的字符

set getRangeKey "Hello learyRedis"
getrange getRangeKey 6 -1
getrange getRangeKey 0 -12

執行結果如下

redis系列:通過demo學習string命令

GETSET

GETSET key value

設置key對應的新value且返回原來key對應的value

getset getSetKey newValue
set getSetKey value
getset getSetKey newValue
get getSetKey

執行結果如下

redis系列:通過demo學習string命令

MGET

MGET key [key …]

返回所有指定的key的value

mset mGetKey1 mGetValue1 mGetKey2 mGetValue2 mGetKey3 mGetValue3
mget mGetKey1 mGetKey2 mGetKey3 mGetKey4

執行結果如下

redis系列:通過demo學習string命令

更新

redis系列:通過demo學習string命令

來看看代碼

@RequestMapping(value = "/updateMyLog",method = RequestMethod.POST)
public boolean updateMyLog(@RequestBody JSONObject myLog){
String myLogId = myLog.getString("id");
myLog.put("updateDate", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
valueOperations.set(MY_LOG_REDIS_KEY_PREFIX+myLogId, myLog.toString());
return true;
}

這裡的set在新增方法裡面講述過,那麼來看看APPEND、STRLEN命令吧

命令介紹
APPEND

APPEND key value

在value的尾部追加新值

redis客戶端執行的命令如下

append appendKey append
append appendKey Value
get appendKey

執行結果如下

redis系列:通過demo學習string命令

STRLEN

STRLEN key

返回value的長度

刪除

redis系列:通過demo學習string命令

代碼如下

@RequestMapping(value = "/delMyLog/{id}", method = RequestMethod.DELETE)
public boolean delMyLog(@PathVariable  String id){
return redisTemplate.delete(MY_LOG_REDIS_KEY_PREFIX + id);
}

可以看到代碼中只用了delete方法,對應著Redis的DEL命令(屬於基本命令)

命令介紹
DEL

DEL key [key …]
刪除key

BIT相關命令

bit命令有SETBIT、GETBIT、BITCOUNT、BITFIELD、BITOP、BITPOS這些。
命令這裡就不做介紹了,直接講述bit相關的案例。

Pattern: real time metrics using bitmaps
BITOP is a good complement to the pattern documented in the BITCOUNT command documentation. Different bitmaps can be combined in order to obtain a target bitmap where the population counting operation is performed.

See the article called “Fast easy realtime metrics using Redis bitmaps” for a interesting use cases.

案例地址Fast easy realtime metrics using Redis bitmaps
網上譯文也有許多,有需要的百度或者google即可

這裡大概講述下使用位圖法統計日登入用戶數、周連續登入用戶數和月連續登入用戶數

位圖法就是bitmap的縮寫,所謂bitmap,就是用每一位來存放某種狀態,適用於大規模數據,但數據狀態又不是很多的情況。通常是用來判斷某個數據存不存在的。 ——來自百度百科

就好像java中int有4個字節,也就是32位。當32位全為1時,也就是int的最大值。

位只能被設置位0或者1,也就是二進制。

java中可以用BitSet來操作位的相關操作

場景

有一萬個用戶,id從1到10000,根據當前是否上線,來設置在第id位上是否為1或者0。通過每天的記錄來統計用戶連續上線的情況。

分析

一號有id為5、3、1的上線了,二號有id為5、4、3的上線了,三號有id為3、2、1的上線了。存儲的數據如下

序號:5 4 3 2 1 0
一號:1 0 1 0 1 0
二號:1 1 1 0 0 0
三號:0 0 1 1 1 0

那麼我們只有將三天的數據進行與操作就可以知道,三天連續上線的有哪些了,與操作的結果如下

序號:5 4 3 2 1 0
結果:0 0 1 0 0 0

很明顯是id為3的用戶連續登入3天。

代碼

先定義一些常量

//存儲的key前綴
private static final String ONLINE_KEY_PREFIX = "online:";
//天數
private static final int DAY_NUM = 30;
//用戶數量
private static final int PEOPLE_NUM = 10000;

然後模擬一個月的數據


public void createData() {
//用來保證線程執行完在進行後面的操作
CountDownLatch countDownLatch = new CountDownLatch(DAY_NUM);
int poolSize = Runtime.getRuntime().availableProcessors() * 2;
ThreadPoolExecutor executor = new ThreadPoolExecutor(poolSize, poolSize, 60, TimeUnit.SECONDS, new ArrayBlockingQueue(DAY_NUM-poolSize));
//DAY_NUM天
for (int i = 1; i <= DAY_NUM; i++) {
int finalI = i;
executor.execute(() -> {
//假設有PEOPLE_NUM個用戶
for (int j = 1; j <= PEOPLE_NUM; j++) {
redisTemplate.opsForValue().setBit(ONLINE_KEY_PREFIX + finalI, j, Math.random() > 0.1);
}
countDownLatch.countDown();
});
}
//等待線程全部執行完成
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

最後是統計

public void calActive(int day) {
if (day < 0 || day > DAY_NUM){
throw new IllegalArgumentException("傳入的天數不能小於0或者大於30天!");
}
long calStart = System.currentTimeMillis();
BitSet active = new BitSet();
active.set(0, PEOPLE_NUM);
for (int i = 1; i <= day; i++) {
BitSet bitSet = BitSet.valueOf(jedis.get((ONLINE_KEY_PREFIX + i).getBytes()));
active.and(bitSet);
}
long calEnd = System.currentTimeMillis();
System.out.println(day + "天的上線用戶" + active.cardinality() + ",花費時長:" + (calEnd - calStart));
}

測試方法

@Test
public void daliyActive() {
/**
*模擬數據
*/
createData();
/**
* 開始統計
*/
//1
calActive(1);
//7
calActive(7);
//15
calActive(15);
//30
calActive(30);
}

測試結果

1天的上線用戶9015,花費時長:0
7天的上線用戶4817,花費時長:0
15天的上線用戶2115,花費時長:0
30天的上線用戶431,花費時長:15

有需要看相關代碼的請點擊GITHUB地址

其他

關於其他相關的命令可以查看下方地址

string全命令

Redis基本命令

命令比較多,但是還是建議學習的人最好每個命令都去敲下,加深印象。
下面詩句送給每一個閱讀的人。

紙上得來終覺淺,絕知此事要躬行。————出自《冬夜讀書示子聿》

相關文章

redis系列:通過文章點贊排名案例學習sortedset命令

redis系列:通過共同好友案例學習set命令

redis系列:通過demo學習list命令

redis系列:通過demo學習hash命令