與Memcached僅支持簡單的key-value結構的數據記錄不一樣,Redis支持的數據類型要豐富得多,經常使用的數據類型主要有五種:String、List、Hash、Set和Sorted Set。html
Redis內部使用一個redisObject對象來表示全部的key和value。redisObject主要的信息包括數據類型(type)、編碼方式(encoding)、數據指針(ptr)、虛擬內存(vm)等。type表明一個value對象具體是何種數據類型,encoding是不一樣數據類型在redis內部式。java
redisObject 對象示意圖redis
下面分別介紹5種數據類型的用法。數組
字符串是Redis值的最基礎的類型。Redis中使用的字符串是經過包裝的,基於c語言字符數組實現的簡單動態字符串(simple dynamic string, SDS)一個抽象數據結構。其源碼定義以下:安全
struct sdshdr {服務器
int len; //len表示buf中存儲的字符串的長度。數據結構
int free; //free表示buf中空閒空間的長度。app
char buf[]; //buf用於存儲字符串內容。dom
};ide
C語言字符串內存結構示意圖1
假設上圖是」hello」字符串的內存結構,這個時候len=5,free=2那麼redis包裝後(sds)其長度爲:
sizeof(struct sdshdr) + len + free + 1
其中buf的大小爲:
len + free + 1
1表示1個字節是用來存儲結束符’\0’的。Redis字符串是二進制安全的,由於二進制數據一般會有中間某個字節存儲’\0’的這種狀況,這意味着一個Redis字符串能夠包含任何種類的數據,例如一個JPEG圖像或者一個序列化的Ruby對象。二進制是否安全,簡單的理解就是能不能在字符串中間有‘\0’,以下圖:
C語言字符串內存結構示意圖2
對於上圖,sds認爲這個字符串是「hello world」,而C語言的字符處理函數認爲這個字符串是「hello」。
String是最經常使用的一種數據類型,普通的key/value存儲均可以歸爲此類。
(1)set——設置key對應的值爲String類型的value
(2)get——獲取key對應的值
192.168.2.129:6379> setnx name lisi
(integer) 0
192.168.2.129:6379> setnx name1 wangwu
(integer) 1
192.168.2.129:6379> get name
"zhangsan"
192.168.2.129:6379> get name1
"wangwu"
192.168.2.129:6379>
(3)mget——批量獲取多個key的值,若是能夠不存在則返回nil
192.168.2.129:6379> mget name name1
1) "zhangsan"
2) "wangwu"
192.168.2.129:6379> mget name name1 name2
1) "zhangsan"
2) "wangwu"
3) (nil)
192.168.2.129:6379>
(4)incr && incrby——incr對key對應的值進行加加操做,並返回新的值;incrby加指定值
192.168.2.129:6379> get age
"20"
192.168.2.129:6379> incr age
(integer) 21
192.168.2.129:6379> set age1 "20"
OK
192.168.2.129:6379> get age1
"20"
192.168.2.129:6379> incr age1
(integer) 21
192.168.2.129:6379> incrby age 3
(integer) 24
從上面的結果能夠看出,咱們對int型的age和string型的age1都能進行incr操做時,
實際上type=string表明value存儲的是一個普通字符串,那麼對應的encoding能夠是raw或者是int,若是是int則表明實際redis內部是按數值型類存儲和表示這個字符串的,固然前提是這個字符串自己能夠用數值表示,好比"20"這樣的字符串,當遇到incr、decr等操做時會轉成數值型進行計算,此時redisObject的encoding字段爲int。若是你試圖對name進行incr操做則報錯。
192.168.2.129:6379> incr name
(error) ERR value is not an integer or out of range
(5)decr && decrby——decr對key對應的值進行減減操做,並返回新的值;decrby減指定值
192.168.2.129:6379> decr age
(integer) 23
192.168.2.129:6379> decrby age 3
(integer) 20
192.168.2.129:6379>
(6)其餘命令
說明 |
|
設置key對應的值爲String類型的value,若是key已經存在則返回0 |
|
setex |
設置key對應的值爲String類型的value,並設定有效期 |
getrange |
獲取key對應value的子字符串 |
mset |
批量設置多個key的值,若是成功表示全部值都被設置,不然返回0表示沒有任何值被設置 |
msetnx |
同mset,不存在就設置,不會覆蓋已有的key |
getset |
設置key的值,並返回key舊的值 |
append |
給指定key的value追加字符串,並返回新字符串的長度 |
strlen |
取指定key的value的長度 |
Hash是一個String類型的field和value之間的映射表,即redis的Hash數據類型的key(hash表名稱)對應的value實際的內部存儲結構爲一個HashMap,所以Hash特別適合存儲對象。相對於把一個對象的每一個屬性存儲爲String類型,將整個對象存儲在Hash類型中會佔用更少內存。
Hash 數據類型內部結構示意圖
當前HashMap的實現有兩種方式:當HashMap的成員比較少時Redis爲了節省內存會採用相似一維數組的方式來緊湊存儲,而不會採用真正的HashMap結構,這時對應的value的redisObject的encoding爲zipmap,當成員數量增大時會自動轉成真正的HashMap,此時encoding爲ht。
用一個對象來存儲用戶信息,商品信息,訂單信息等等。
(1)hset——設置key對應的HashMap中的field的value
(2)hget——獲取key對應的HashMap中的field的value
192.168.2.129:6379> hset myhash name zhangsan
(integer) 1
192.168.2.129:6379> hset myhash age 20
(integer) 1
192.168.2.129:6379> hget myhash name
"zhangsan"
192.168.2.129:6379> hget myhash age
"20"
192.168.2.129:6379>
(3)hgetall——獲取key對應的HashMap中的全部field的value
192.168.2.129:6379> hgetall myhash
1) "name"
2) "zhangsan"
3) "age"
4) "20"
192.168.2.129:6379>
(4)其它命令
說明 |
|
hsetnx |
設置key對應的HashMap中的field的value,若是不存在則先建立 |
hmset |
|
hmget |
批量獲取key對應的HashMap中的field的value |
hincrby |
給key對應的HashMap中的field的value加指定的值 |
hexits |
測試key對應的HashMap中的field是否存在 |
hlen |
|
hdel |
刪除key對應的HashMap中的field |
hkeys |
|
hvals |
返回key對應的HashMap中全部的field的value |
Redis的List類型其實就是每個元素都是String類型的雙向鏈表。咱們能夠從鏈表的頭部和尾部添加或者刪除元素。這樣的List既能夠做爲棧,也能夠做爲隊列使用。
List數據結構內部示意圖
如好友列表,粉絲列表,消息隊列,最新消息排行等。
(1)lpush——在key對應的list的頭部添加一個元素。
(2)lrange——獲取key對應的list的指定下標範圍的元素,-1表示獲取全部元素。
(3)lpop——從key對應的list的尾部刪除一個元素,並返回該元素。
192.168.2.129:6379> lpush newlist news1 news2 news3
(integer) 3
192.168.2.129:6379> lrange newlist 0 -1
1) "news3"
2) "news2"
3) "news1"
192.168.2.129:6379> lpop newlist
"news3"
192.168.2.129:6379> lrange newlist 0 -1
1) "news2"
2) "news1"
192.168.2.129:6379>
從上面的操做能夠看出,lpush、lpop從表頭操做。
(4)rpush——在key對應的list的尾部添加一個元素。
(5)rpop——從key對應的list的尾部刪除一個元素,並返回該元素。
192.168.2.129:6379> rpush newlist2 news1 news2 news3
(integer) 3
192.168.2.129:6379> lrange newlist2 0 -1
1) "news1"
2) "news2"
3) "news3"
192.168.2.129:6379> rpop newlist2
"news3"
192.168.2.129:6379>
從上面的操做能夠看出,rpush、rpop從表尾操做。
(6)其餘命令
說明 |
|
linsert |
在key對應的list的特定元素的前或後插入元素 |
lset |
設置key對應的list中指定下標元素的值 |
lrem |
從key對應的list中刪除n個和value相同的元素 |
ltrim |
保留key對應的list中指定範圍的元素 |
rpoplpush |
從第一個list的尾部移除一個元素並添加到第二個list的頭部 |
llen |
|
lindex |
返回key對應的list中index的元素 |
Redis 集合(Set類型)是一個無序的String類型數據的集合,相似List的一個列表,與List不一樣的是Set不能有重複的數據。實際上,Set的內部是用HashMap實現的,Set只用了HashMap的key列來存儲對象。咱們來看看java中HashSet的源碼:
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
static final long serialVersionUID = -5024744406713321676L;
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
......
/**
* Returns an iterator over the elements in this set. The elements
* are returned in no particular order.
*
* @return an Iterator over the elements in this set
* @see ConcurrentModificationException
*/
public Iterator<E> iterator() {
return map.keySet().iterator();
}
可見建立一個HashSet的時候實際上建立了一個HashMap;Set中的元素,只是存放在了底層HashMap的key上,底層HashMap的value列爲空,遍歷HashSet的時候從HashMap中取出keySet來遍歷。
Set底層結構示意圖
集合有取交集、並集、差集等操做,所以能夠求共同好友、共同興趣、分類標籤等。
(1)sadd——在key對應的set中添加一個元素。
(2)smembers——獲取key對應的set的全部元素。
(3)spop——隨機返回並刪除key對應的set中的一個元素。
192.168.2.129:6379> sadd myset news1 news2 news3
(integer) 3
192.168.2.129:6379> smembers myset
1) "news3"
2) "news2"
3) "news1"
192.168.2.129:6379> spop myset
"news3"
192.168.2.129:6379>
(4)sdiff——求給定key對應的set與第一個key對應的set的差集
192.168.2.129:6379> smembers myset
1) "news3"
2) "news2"
3) "news1"
192.168.2.129:6379> sadd myset2 news3 news4 news5
(integer) 3
192.168.2.129:6379> smembers myset2
1) "news4"
2) "news3"
3) "news5"
192.168.2.129:6379> sdiff myset myset2
1) "news1"
2) "news2"
192.168.2.129:6379>
(5)suion——求給定key對應的set並集
192.168.2.129:6379> sunion myset myset2
1) "news3"
2) "news1"
3) "news2"
4) "news4"
5) "news5"
192.168.2.129:6379>
192.168.2.129:6379> sinter myset myset2
1) "news3"
192.168.2.129:6379>
(7)其餘命令
說明 |
|
srem |
刪除key對應的set中的一個元素 |
sdiffstore |
求給定key對應的set與第一個key對應的set的差集,並存儲到另外一個key對應的set中 |
sinterstore |
求給定key對應的set交集,並存儲到另外一個key對應的set中 |
suionstore |
求給定key對應的set並集,並存儲到另外一個key對應的set中 |
somve |
從第一個key對應的set中刪除指定元素並添加到第二個key對應的set中 |
scard |
|
sismember |
測試某個元素是否爲key對應的set中的元素個數 |
srandmember |
隨機返回key對應的set中的一個元素,但不刪除元素 |
SortSet顧名思義,是一個排好序的Set,它在Set的基礎上增長了一個順序屬性score,這個屬性在添加修改元素時能夠指定,每次指定後,SortSet會自動從新按新的值排序。
sorted set的內部使用HashMap和跳躍表(SkipList)來保證數據的存儲和有序,HashMap裏放的是成員到score的映射,而跳躍表裏存放的是全部的成員,排序依據是HashMap裏存的score。
如按時間排序的時間軸。
(1)zadd ——在key對應的zset中添加一個元素
(2)zrange——獲取key對應的zset中指定範圍的元素,-1表示獲取全部元素
192.168.2.129:6379> zadd myzset 1 "one" 2 "two" 3 "three"
(integer) 3
192.168.2.129:6379> zrange myzset 0 -1
1) "one"
2) "two"
3) "three"
192.168.2.129:6379> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
192.168.2.129:6379>
(3)zrem——刪除key對應的zset中的一個元素
192.168.2.129:6379> zrem myzset one
(integer) 1
192.168.2.129:6379> zrange myzset 0 -1 withscores
1) "two"
2) "2"
3) "three"
4) "3"
192.168.2.129:6379>
(4)其它命令
命令 |
說明 |
zincrby |
若是key對應的zset中已經存在元素member,則對member的score屬性加指定的值 |
zrank |
返回key對應的zset中指定member的排名。其中member按score值遞增(從小到大);排名以0爲底,也就是說,score值最小的成員排名爲0 |
得到成員按score值遞減(從大到小)排列的排名 |
|
返回有序集key中,指定區間內的成員。其中成員的位置按score值遞減(從大到小)來排列 |
|
返回有序集key中,指定分數範圍的元素列表 |
|
zcount |
返回有序集key中,score值在min和max之間(默認包括score值等於min或max)的成員 |
zcard |
返回key的有序集元素個數 |
keys/exits/del/expire/ttl/move/persist/randomkey/rename/type
ping/echo/select/quit/dbsize/info/config get/flushdb/flushall
這些命令都很容易使用,就不舉例說明了。到此,redis的數據類型以及經常使用命令已經介紹完畢,下一篇咱們將學習redis的一些高級特性。
http://www.redis.cn/documentation.html