該文章將經過一個小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 key
對存儲在指定key的數值執行原子的加1操做。沒有對應的key則設置爲0,再相加
INCRBY key increment
其實和INCR相似,不一樣的是這個命令能夠指定具體加多少
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 提供了EX
、PX
、NX
、XX
參數用於取代SETEX、SETNX和PSETEX,後續版本可能會移除SETEX、SETNX和PSETEX命令。下面是官網的原話
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 key value [expiration EX seconds|PX milliseconds] [NX|XX]
設置鍵key對應value
參數選項
EX seconds – 設置鍵key的過時時間,單位時秒
PX milliseconds – 設置鍵key的過時時間,單位時毫秒
NX – 只有鍵key不存在的時候纔會設置key的值
XX – 只有鍵key存在的時候纔會設置key的值
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 key value [key value ...]
同時設置多個key、value
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 pattern
查找全部符合給定模式pattern(正則表達式)的 key
GET key
獲取key對應的value
set getKey getValue get getKey
執行結果以下
GETRANGE key start end
獲取start到end之間的字符
set getRangeKey "Hello learyRedis" getrange getRangeKey 6 -1 getrange getRangeKey 0 -12
執行結果以下
GETSET key value
設置key對應的新value且返回原來key對應的value
getset getSetKey newValue set getSetKey value getset getSetKey newValue get getSetKey
執行結果以下
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 key value
在value的尾部追加新值
redis客戶端執行的命令以下
append appendKey append append appendKey Value get appendKey
執行結果以下
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 key [key ...]
刪除key
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地址
關於其餘相關的命令能夠查看下方地址
命令比較多,可是仍是建議學習的人最好每一個命令都去敲下,加深印象。
下面詩句送給每個閱讀的人。
紙上得來終覺淺,絕知此事要躬行。————出自《冬夜讀書示子聿》