Redis从入门到放弃系列(一) String
Redis從入門到放棄系列(一) String
本文例子基于:5.0.4 字符串是Redis中最常見的數(shù)據(jù)結(jié)構(gòu),底層是采用SDS,是可以修改的字符串,類似ArrayList,采用預(yù)分配冗余空間的方式來減少內(nèi)存的頻繁分配。
首先讓我們來看一下該如何在redis里面使用字符串這種類型
// 將字符串 value 關(guān)聯(lián)到 key // 如果key 已經(jīng)有值了,直接覆蓋 emmmm.跟我們使用HashMap是不是很像~ // 如果已經(jīng)存在一個(gè)帶有過期時(shí)間的key,我們重新set會(huì)將原先的過期時(shí)間清除 (重點(diǎn)) >set key value [expiration EX seconds|PX milliseconds] [NX|XX] 復(fù)制代碼可選參數(shù):[expiration EX seconds|PX milliseconds] [NX|XX]
我們發(fā)現(xiàn) set 方法存在兩個(gè)可選參數(shù) [expiration EX seconds|PX milliseconds] 跟 [NX|XX]
>EX seconds:將鍵的過期時(shí)間設(shè)置為 seconds 秒。 執(zhí)行 SET key value EX seconds 的效果等同于執(zhí)行 SETEX key seconds value >PX milliseconds:將鍵的過期時(shí)間設(shè)置為 milliseconds 毫秒。 執(zhí)行 SET key value PX milliseconds 的效果等同于執(zhí)行 PSETEX key milliseconds value >NX:只在鍵不存在時(shí), 才對(duì)鍵進(jìn)行設(shè)置操作。 執(zhí)行 SET key value NX 的效果等同于執(zhí)行 SETNX key value >XX:只在鍵已經(jīng)存在時(shí), 才對(duì)鍵進(jìn)行設(shè)置操作 復(fù)制代碼##代碼示例:
//對(duì)不存在的健設(shè)置 >set name "black-search" OK >get name "black-search" ---------------------------------- //對(duì)已經(jīng)存在的值設(shè)置 >set name "new-black-search" OK >get name "new-black-search" ---------------------------------- //使用 ex seconds >set name "black-search" ex 10 OK >get name "black-search" //獲取key的有效時(shí)間 >ttl name (integer) 6 //稍微等一會(huì)再執(zhí)行下面的命令 >get name (nil) ---------------------------------- // 使用nx >set name "black-search" nx OK >set name "black-search" nx (nil) ---------------------------------- // 使用xx >set name "new-black-search" xx OK //讓我們設(shè)置一個(gè)不存在的key >set key value xx (nil) 復(fù)制代碼至此,redisset的用法先告一段落.
debug object key
我們在使用redis進(jìn)行普通的set處理的時(shí)候,我們會(huì)使用一下這樣子的方式去設(shè)置:
>set name "black-search" OK // redis提供的調(diào)試 api >debug object name Value at:0x179d060 refcount:1 encoding:embstr serializedlength:13 lru:14160370 lru_seconds_idle:17 復(fù)制代碼從上面的輸出我們重點(diǎn)關(guān)注一下serializedlength:13,我們輸入的明明長度就只有12,為嘛會(huì)輸出13呢~ 其實(shí)是redis里面幫我們做了處理,redis會(huì)在字符的結(jié)尾使用'\0'結(jié)尾
因?yàn)閭鹘y(tǒng)C字符串符合ASCII編碼,這種編碼的操作的特點(diǎn)就是:遇零則止 。即,當(dāng)讀一個(gè)字符串時(shí),只要遇到’\0’結(jié)尾,就認(rèn)為到達(dá)末尾,就忽略’\0’結(jié)尾以后的所有字符。因此,如果傳統(tǒng)字符串保存圖片,視頻等二進(jìn)制文件,操作文件時(shí)就被截?cái)嗔?所以在這里讀者是不是也像我一樣去實(shí)踐了?
127.0.0.1:6379> set name "ssssssss\0 asdasdasdasd" OK 127.0.0.1:6379> get name "ssssssss0 asdasdasdasd" 127.0.0.1:6379> set name "asdasdasd \\0 asdasdasdasd " OK 127.0.0.1:6379> get name "asdasdasd \\0 asdasdasdasd " 127.0.0.1:6379> set name "asdasdasd'\0' asdasdasdasdasd" OK 127.0.0.1:6379> get name "asdasdasd'0' asdasdasdasdasd" 127.0.0.1:6379> set name "asdasdasd '\\0'asdasdasd" OK 127.0.0.1:6379> get name "asdasdasd '\\0'asdasdasd" 復(fù)制代碼哈哈,其實(shí)這里redis已經(jīng)做了過濾了呢~
sds sdscatrepr(sds s, const char *p, size_t len) {s = sdscatlen(s,"\"",1);while(len--) {switch(*p) {case '\\':case '"':s = sdscatprintf(s,"\\%c",*p);break;case '\n': s = sdscatlen(s,"\\n",2); break;case '\r': s = sdscatlen(s,"\\r",2); break;case '\t': s = sdscatlen(s,"\\t",2); break;case '\a': s = sdscatlen(s,"\\a",2); break;case '\b': s = sdscatlen(s,"\\b",2); break;default:if (isprint(*p))s = sdscatprintf(s,"%c",*p);elses = sdscatprintf(s,"\\x%02x",(unsigned char)*p);break;}p++;}return sdscatlen(s,"\"",1); } 復(fù)制代碼回到開頭
我們說字符串類似Java的ArrayList,那么它每次是怎樣擴(kuò)容呢?
//sds.h //sds.c sds sdsMakeRoomFor(sds s, size_t addlen) {void *sh, *newsh;size_t avail = sdsavail(s);size_t len, newlen;char type, oldtype = s[-1] & SDS_TYPE_MASK;int hdrlen;/* Return ASAP if there is enough space left. */if (avail >= addlen) return s;len = sdslen(s);sh = (char*)s-sdsHdrSize(oldtype);newlen = (len+addlen);if (newlen < SDS_MAX_PREALLOC)newlen *= 2;elsenewlen += SDS_MAX_PREALLOC;type = sdsReqType(newlen);/* Don't use type 5: the user is appending to the string and type 5 is* not able to remember empty space, so sdsMakeRoomFor() must be called* at every appending operation. */if (type == SDS_TYPE_5) type = SDS_TYPE_8;hdrlen = sdsHdrSize(type);if (oldtype==type) {newsh = s_realloc(sh, hdrlen+newlen+1);if (newsh == NULL) return NULL;s = (char*)newsh+hdrlen;} else {/* Since the header size changes, need to move the string forward,* and can't use realloc */newsh = s_malloc(hdrlen+newlen+1);if (newsh == NULL) return NULL;memcpy((char*)newsh+hdrlen, s, len+1);s_free(sh);s = (char*)newsh+hdrlen;s[-1] = type;sdssetlen(s, len);}sdssetalloc(s, newlen);return s; } 復(fù)制代碼從上面的代碼可以看到,當(dāng)字符串長度小于 1M 時(shí),擴(kuò)容都是加倍現(xiàn)有的空間,如果超過 1M,擴(kuò)容時(shí)一次只會(huì)多擴(kuò) 1M 的空間。(字符串最大長度為 512M)
應(yīng)用場景
1.儲(chǔ)存業(yè)務(wù)數(shù)據(jù)
>set user:1 '{"id":1,"name":"黑搜丶D","wechat":"black-search"}' 復(fù)制代碼2.自增ID 當(dāng) value的值為整數(shù)類型時(shí),redis可以把它當(dāng)做是整數(shù)一樣進(jìn)行自增(incr)自減(decr)操作。由于 redis 所有的操作都是原子性的,所以不必?fù)?dān)心多客戶端連接時(shí)可能出現(xiàn)的事務(wù)問題。
總結(jié)
以上是生活随笔為你收集整理的Redis从入门到放弃系列(一) String的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 跳出误区:Java程序员进阶架构师真的没
- 下一篇: 【团队】 冲刺一(9/10)