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

前言

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

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

若是須要詳細瞭解該項目的其餘部分,請點擊下方項目Github地址git

項目Github地址:https://github.com/rainbowda/learnWay/tree/master/learnRedis/case-stringgithub

案例

demo功能是記錄日誌,整個demo的大體頁面以下正則表達式

準備工做

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

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

日誌相關的key將會以myLog:一、myLog:二、myLog:3的形式存儲spring

redis操做對象springboot

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

新增

先來看看gif圖吧前端框架

來看看後臺的方法app

@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

執行結果以下

下面是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

執行結果以下

下面是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

執行結果以下

GETRANGE
GETRANGE key start end

獲取start到end之間的字符

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

執行結果以下

GETSET
GETSET key value

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

getset getSetKey newValue
set getSetKey value
getset getSetKey newValue
get getSetKey

執行結果以下

MGET
MGET key [key ...]

返回全部指定的key的value

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

執行結果以下

更新

來看看代碼

@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

執行結果以下

STRLEN
STRLEN key

返回value的長度

刪除

代碼以下

@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爲五、三、1的上線了,二號有id爲五、四、3的上線了,三號有id爲三、二、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基本命令

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

紙上得來終覺淺,絕知此事要躬行。————出自《冬夜讀書示子聿》
相關文章
相關標籤/搜索