redis系列:通過demo學(xué)習(xí)string命令

前言

該文章將通過一個(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命令操作說明。

如果需要詳細(xì)了解該項(xiàng)目的其他部分肩豁,請(qǐng)點(diǎn)擊下方項(xiàng)目Github地址

項(xiàng)目Github地址:https://github.com/rainbowda/learnWay/tree/master/learnRedis/case-string

案例

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

[圖片上傳失敗...(image-db453e-1531962915212)]

準(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;

新增

先來看看gif圖吧

[圖片上傳失敗...(image-351c3a-1531962915213)]

來看看后臺(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é)果如下

[圖片上傳失敗...(image-bb63d3-1531962915213)]

下面是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 香府、PX 董栽、NXXX參數(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的過期時(shí)間擒抛,單位時(shí)秒
PX milliseconds – 設(shè)置鍵key的過期時(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é)果如下

[圖片上傳失敗...(image-c47b78-1531962915213)]

下面是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)容查詢出來

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

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

命令介紹
KEYS

KEYS pattern

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

GET

GET key

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

set getKey getValue
get getKey

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

[圖片上傳失敗...(image-df89a1-1531962915213)]

GETRANGE

GETRANGE key start end

獲取start到end之間的字符

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

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

[圖片上傳失敗...(image-6bc7ec-1531962915213)]

GETSET

GETSET key value

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

getset getSetKey newValue
set getSetKey value
getset getSetKey newValue
get getSetKey

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

[圖片上傳失敗...(image-636c07-1531962915213)]

MGET

MGET key [key ...]

返回所有指定的key的value

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

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

[圖片上傳失敗...(image-1a5826-1531962915213)]

更新

[圖片上傳失敗...(image-85fa7c-1531962915213)]

來看看代碼

@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客戶端執(zhí)行的命令如下

append appendKey append
append appendKey Value
get appendKey

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

[圖片上傳失敗...(image-3437ea-1531962915213)]

STRLEN

STRLEN key

返回value的長(zhǎng)度

刪除

[圖片上傳失敗...(image-e84976-1531962915213)]

代碼如下

@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" for a interesting use cases.

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

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

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

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

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

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

場(chǎng)景

有一萬(wàn)個(gè)用戶攒至,id從1到10000,根據(jù)當(dāng)前是否上線躁劣,來設(shè)置在第id位上是否為1或者0嗓袱。通過每天的記錄來統(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() {
    //用來保證線程執(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)代碼的請(qǐng)點(diǎn)擊GITHUB地址

其他

關(guān)于其他相關(guān)的命令可以查看下方地址

string全命令

Redis基本命令

命令比較多荆几,但是還是建議學(xué)習(xí)的人最好每個(gè)命令都去敲下,加深印象赊时。
下面詩(shī)句送給每一個(gè)閱讀的人吨铸。

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市竭缝,隨后出現(xiàn)的幾起案子房维,更是在濱河造成了極大的恐慌,老刑警劉巖抬纸,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咙俩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡湿故,警方通過查閱死者的電腦和手機(jī)暴浦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晓锻,“玉大人歌焦,你說我怎么就攤上這事⊙舛撸” “怎么了独撇?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)躁锁。 經(jīng)常有香客問我纷铣,道長(zhǎng),這世上最難降的妖魔是什么战转? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任搜立,我火速辦了婚禮,結(jié)果婚禮上槐秧,老公的妹妹穿的比我還像新娘啄踊。我一直安慰自己,他們只是感情好刁标,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布颠通。 她就那樣靜靜地躺著,像睡著了一般膀懈。 火紅的嫁衣襯著肌膚如雪顿锰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音硼控,去河邊找鬼刘陶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛牢撼,可吹牛的內(nèi)容都是我干的匙隔。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼浪默,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼牡直!你這毒婦竟也來了缀匕?” 一聲冷哼從身側(cè)響起纳决,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乡小,沒想到半個(gè)月后阔加,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡满钟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年胜榔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片湃番。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡夭织,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吠撮,到底是詐尸還是另有隱情尊惰,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布泥兰,位于F島的核電站弄屡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鞋诗。R本人自食惡果不足惜膀捷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望削彬。 院中可真熱鬧全庸,春花似錦、人聲如沸融痛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)危虱。三九已至,卻和暖如春酗失,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背墩崩。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工氓英, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鹦筹。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓铝阐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親铐拐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子徘键,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容