溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何通過(guò)日志案例學(xué)習(xí)string命令

發(fā)布時(shí)間:2021-11-11 17:07:29 來(lái)源:億速云 閱讀:147 作者:柒染 欄目:云計(jì)算

這篇文章給大家介紹如何通過(guò)日志案例學(xué)習(xí)string命令,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。

小編將通過(guò)一個(gè)小demo將講述Redis中的string類型命令。demo將以springboot為后臺(tái)框架快速開發(fā),iview前端框架進(jìn)行簡(jiǎn)單的頁(yè)面設(shè)計(jì),為了方便就不使用DB存儲(chǔ)數(shù)據(jù)了,直接采用Redis作為存儲(chǔ)。

文中不會(huì)講述springboot用法及項(xiàng)目搭建部分。直接根據(jù)功能方面進(jìn)行講述,穿插string命令操作說(shuō)明。

案例

demo功能是記錄日志,整個(gè)demo的大致頁(yè)面如下

如何通過(guò)日志案例學(xué)習(xí)string命令

準(zhǔn)備工作

首先定義一個(gè)key的前綴,已經(jīng)存儲(chǔ)自增id的key

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

日志相關(guān)的key將會(huì)以myLog:1、myLog:2、myLog:3的形式存儲(chǔ)

redis操作對(duì)象

private RedisTemplate redisTemplate;
//string 命令操作對(duì)象
private ValueOperations valueOperations;
新增

先來(lái)看看gif圖吧

來(lái)看看后臺(tái)的方法

@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);
    //將數(shù)據(jù)寫到redis中
    valueOperations.set(MY_LOG_REDIS_KEY_PREFIX+myLogId, myLog.toString());

    return true;
}

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

valueOperations.increment(MY_LOG_REDIS_ID_KEY, 1);

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

命令介紹

valueOperations.increment其實(shí)就相當(dāng)于Redis中的INCR、INCRBY、INCRBYFLOAT、DECR、DECRBY

INCR

INCR key

對(duì)存儲(chǔ)在指定key的數(shù)值執(zhí)行原子的加1操作。沒有對(duì)應(yīng)的key則設(shè)置為0,再相加

INCRBY

INCRBY key increment

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

INCRBYFLOAT

INCRBYFLOAT key increment

也是類似的,不同的是加的數(shù)值是浮點(diǎn)數(shù)

incrbyfloat incrByFloatKey 5.11
incrbyfloat incrByFloatKey 5.22

執(zhí)行結(jié)果如下

如何通過(guò)日志案例學(xué)習(xí)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就是對(duì)應(yīng)Redis的SET命令了,相關(guān)聯(lián)的還有SETEX、SETNX和PSETEX。需要注意的是set在Redis版本2.6.12 提供了EX 、PXNX 、XX參數(shù)用于取代SETEX、SETNX和PSETEX,后續(xù)版本可能會(huì)移除SETEX、SETNX和PSETEX命令。下面是官網(wǎng)的原話

Since the SET command options can replace SETNX, SETEX, PSETEX, 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]

設(shè)置鍵key對(duì)應(yīng)value
參數(shù)選項(xiàng)

EX seconds – 設(shè)置鍵key的過(guò)期時(shí)間,單位時(shí)秒

PX milliseconds – 設(shè)置鍵key的過(guò)期時(shí)間,單位時(shí)毫秒
NX – 只有鍵key不存在的時(shí)候才會(huì)設(shè)置key的值
XX – 只有鍵key存在的時(shí)候才會(huì)設(shè)置key的值

SETRANGE

SETRANGE key offset value

替換從指定長(zhǎng)度開始的字符

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

執(zhí)行結(jié)果如下

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

同時(shí)設(shè)置多個(gè)key、value

 MSETNX

MSETNX key value [key value ...]

同時(shí)設(shè)置多個(gè)key、value,key存在則忽略

查詢

接著寫個(gè)查詢方法,將新增的內(nèi)容查詢出來(lái)

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

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

命令介紹

KEYS

KEYS pattern

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

GET

GET key

獲取key對(duì)應(yīng)的value

set getKey getValue
get getKey

執(zhí)行結(jié)果如下

如何通過(guò)日志案例學(xué)習(xí)string命令

GETRANGE

GETRANGE key start end

獲取start到end之間的字符

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

執(zhí)行結(jié)果如下

GETSET

GETSET key value

設(shè)置key對(duì)應(yīng)的新value且返回原來(lái)key對(duì)應(yīng)的value

getset getSetKey newValue
set getSetKey value
getset getSetKey newValue
get getSetKey

執(zhí)行結(jié)果如下

如何通過(guò)日志案例學(xué)習(xí)string命令

MGET

MGET key [key ...]

返回所有指定的key的value

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

執(zhí)行結(jié)果如下

如何通過(guò)日志案例學(xué)習(xí)string命令

來(lái)看看代碼

@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在新增方法里面講述過(guò),那么來(lái)看看APPEND、STRLEN命令吧

命令介紹

APPEND

APPEND key value

在value的尾部追加新值

redis客戶端執(zhí)行的命令如下

append appendKey append
append appendKey Value
get appendKey

執(zhí)行結(jié)果如下

如何通過(guò)日志案例學(xué)習(xí)string命令

代碼如下

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

可以看到代碼中只用了delete方法,對(duì)應(yīng)著Redis的DEL命令(屬于基本命令)

命令介紹

DEL

DEL key [key ...]

刪除key

BIT相關(guān)命令

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

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">

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

這里大概講述下使用位圖法統(tǒng)計(jì)日登入用戶數(shù)、周連續(xù)登入用戶數(shù)和月連續(xù)登入用戶數(shù)

位圖法就是bitmap的縮寫,所謂bitmap,就是用每一位來(lái)存放某種狀態(tài),適用于大規(guī)模數(shù)據(jù),但數(shù)據(jù)狀態(tài)又不是很多的情況。通常是用來(lái)判斷某個(gè)數(shù)據(jù)存不存在的。 ------來(lái)自百度百科

就好像java中int有4個(gè)字節(jié),也就是32位。當(dāng)32位全為1時(shí),也就是int的最大值。

位只能被設(shè)置位0或者1,也就是二進(jìn)制。

java中可以用BitSet來(lái)操作位的相關(guān)操作

場(chǎng)景

有一萬(wàn)個(gè)用戶,id從1到10000,根據(jù)當(dāng)前是否上線,來(lái)設(shè)置在第id位上是否為1或者0。通過(guò)每天的記錄來(lái)統(tǒng)計(jì)用戶連續(xù)上線的情況。

分析

一號(hào)有id為5、3、1的上線了,二號(hào)有id為5、4、3的上線了,三號(hào)有id為3、2、1的上線了。存儲(chǔ)的數(shù)據(jù)如下

序號(hào):5 4 3 2 1 0
一號(hào):1 0 1 0 1 0
二號(hào):1 1 1 0 0 0
三號(hào):0 0 1 1 1 0

那么我們只有將三天的數(shù)據(jù)進(jìn)行與操作就可以知道,三天連續(xù)上線的有哪些了,與操作的結(jié)果如下

序號(hào):5 4 3 2 1 0
結(jié)果:0 0 1 0 0 0

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

代碼

先定義一些常量

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

然后模擬一個(gè)月的數(shù)據(jù)

public void createData() {
    //用來(lái)保證線程執(zhí)行完在進(jìn)行后面的操作
    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(() -> {
            //假設(shè)有PEOPLE_NUM個(gè)用戶
            for (int j = 1; j <= PEOPLE_NUM; j++) {
                redisTemplate.opsForValue().setBit(ONLINE_KEY_PREFIX + finalI, j, Math.random() > 0.1);
            }
            countDownLatch.countDown();
        });
    }

    //等待線程全部執(zhí)行完成
    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

最后是統(tǒng)計(jì)

public void calActive(int day) {
    if (day < 0 || day > DAY_NUM){
        throw new IllegalArgumentException("傳入的天數(shù)不能小于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() + ",花費(fèi)時(shí)長(zhǎng):" + (calEnd - calStart));
}

測(cè)試方法

@Test
public void daliyActive() {
    /**
     *模擬數(shù)據(jù)
     */
    createData();

    /**
     * 開始統(tǒng)計(jì)
     */
    //1
    calActive(1);

    //7
    calActive(7);

    //15
    calActive(15);

    //30
    calActive(30);
}

測(cè)試結(jié)果

1天的上線用戶9015,花費(fèi)時(shí)長(zhǎng):0
7天的上線用戶4817,花費(fèi)時(shí)長(zhǎng):0
15天的上線用戶2115,花費(fèi)時(shí)長(zhǎng):0
30天的上線用戶431,花費(fèi)時(shí)長(zhǎng):15

關(guān)于如何通過(guò)日志案例學(xué)習(xí)string命令就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI