目錄
- Redis和Memcached對(duì)比
- 基本命令
- 場(chǎng)景1:統(tǒng)計(jì)每個(gè)用戶的登錄天數(shù)
- 場(chǎng)景2:電商網(wǎng)站派發(fā)禮物
- 更多命令
- 通過(guò)管道連接Redis發(fā)送命令
- 發(fā)布/訂閱功能
- Redis的事務(wù)
- 為什么 Redis 的事務(wù)不支持回滾(roll back)
Redis和Memcached對(duì)比
其中有一個(gè)比較重要的區(qū)別是關(guān)于其提供的數(shù)據(jù)結(jié)構(gòu)區(qū)別
Memcached
在其數(shù)據(jù)結(jié)構(gòu)中僅使用字符串和整數(shù)。因此,您保存的所有內(nèi)容都可以是字符串或整數(shù)。它很復(fù)雜,因?yàn)閷?duì)于整數(shù),您可以做的唯一數(shù)據(jù)操作是添加或減去它們。如果需要保存數(shù)組或?qū)ο螅瑒t必須先將它們序列化然后保存。要閱讀它們,您需要取消序列化。
Redis
具有更強(qiáng)大的數(shù)據(jù)結(jié)構(gòu),它不僅可以處理字符串整數(shù),還可以處理二進(jìn)制安全字符串,二進(jìn)制安全字符串列表,二進(jìn)制安全字符串集和有序集。
關(guān)于Redis的數(shù)據(jù)結(jié)構(gòu):https://zhuanlan.zhihu.com/p/270592490
基本命令
# 如果k1的值設(shè)置過(guò),就不設(shè)置,如果k1的值沒(méi)有設(shè)置,才會(huì)設(shè)置k1的值為hello
# msetnx 同理
set k1 hello nx
# 如果k2沒(méi)設(shè)置,就不能設(shè)置k2的值為hello,如果k2的值設(shè)置過(guò),才能把他設(shè)置過(guò)hello
set k2 hello xx
# 設(shè)置多個(gè)值,其中把k1設(shè)置xx,把k2設(shè)置為33
mset k1 xx k2 33
# 拼接字符串
APPEND k1 " world"
# 范圍查找(從0開(kāi)始)
GETRANGE k1 0 1
# 范圍查找(逆序,最右邊編號(hào)從-1開(kāi)始)
# 所以0,-1 就是拿到整個(gè)字符串
GETRANGE k1 0 -1
# 把k1字符串的第1個(gè)(從第0個(gè)位置開(kāi)始)用xxx開(kāi)始替換后續(xù)的字符
# 如果k1是hello,那么執(zhí)行完下面的語(yǔ)句,k1會(huì)被設(shè)置為:hxxxo
SETRANGE k1 1 xxx
# 獲取k1字符串的長(zhǎng)度
STRLEN k1
# 獲取數(shù)據(jù)類型
TYPE k1
# 查詢某個(gè)命令的使用,如下命令,就是查詢SET命令如何使用
help SET
# k1的值+1
INCR k1
# k1的值+22
INCRBY k1 22
# k1的值-1
DECR k1
# k1的值-22
DECRBY k1 22
# k1的值+0.5
INCRBYFLOAT k1 0.5
# 可以使用--raw選項(xiàng)在終端上強(qiáng)制進(jìn)行原始輸出
127.0.0.1:6379> set k3 中
OK
127.0.0.1:6379> get k3
"\xe4\xb8\xad"
127.0.0.1:6379> exit
[root@node1 utils]# redis-cli --raw
127.0.0.1:6379> get k3
中
# 獲取k1的值,然后把k1的值設(shè)置為hello
GETSET k1 hello
# 設(shè)置k1的值為a,如果要把k1的值變?yōu)閎,也可以通過(guò)setbit操作
# 也就是將 01100001 變成 01100010 (a的ASCII碼是97,b的ASCII碼是98),也就是將'a'中的offset 6從0變成1,將offset 7 從1變成0 (從0開(kāi)始算)
set k1 a
setbit k1 6 1
setbit k1 7 0
# 查找字符串里面bit值為1的位置 (從左邊開(kāi)始數(shù))
set k1 a
bitpos k1 1
結(jié)果為:1
# bitpos的 start end指的是字節(jié)位置
# 查找字符串里面bit值為1從第0個(gè)字節(jié)開(kāi)始的位置
set k1 ab
BITPOS k1 1 0
1
# 查找字符串里面bit值為0從第1個(gè)字節(jié)開(kāi)始的位置
# 其中9的ASCII碼為00111001 a的ascii碼為01100001
# 所以a9的ASCII碼為01100001 00111001
# BITPOS k1 0 1取的位置就是:01100001 ‘0'0111001 中‘'圈住的位置
set k1 a9
BITPOS k1 0 1
9
# BITPOS找不到則返回-1
# 例如:查找字符串里面bit值為1的位置
set k1 "\x00\x00\x00"
BITPOS k1 1
-1
# bitcount統(tǒng)計(jì)的是1的數(shù)量, bitcount key [start, end] , 其中的start和end指的是byte位置而非bit位置。
# a的ASCII碼為01100001
set k1 a
bitcount k1
3
場(chǎng)景1:統(tǒng)計(jì)每個(gè)用戶的登錄天數(shù)
假設(shè)jack這名用戶,分別在第6天,第23天,第134天,和第364天登錄了系統(tǒng)。
可以執(zhí)行如下命令:
setbit jack 6 1setbit jack 23 1setbit jack 134 1setbit jack 364 1
統(tǒng)計(jì)jack登錄的天數(shù),直接可以通過(guò):
bitcount jack
場(chǎng)景2:電商網(wǎng)站派發(fā)禮物
假設(shè)某個(gè)電商網(wǎng)站做活動(dòng),在某天要派送禮物,假設(shè)這個(gè)網(wǎng)站有2億用戶,請(qǐng)問(wèn)應(yīng)該備貨多少禮物比較適合
思路:
首先,可以考慮一下統(tǒng)計(jì)整個(gè)網(wǎng)站的活躍用戶有多少,比如我們?cè)O(shè)置三天,1號(hào),2號(hào),3號(hào),統(tǒng)計(jì)三天登錄的用戶獲得一個(gè)近似的活躍用戶的數(shù)量:
# 編號(hào)為2的用戶登在2019年1月1號(hào)錄了一次
setbit 20190101 2 1
# 編號(hào)為3的用戶在2019年1月2號(hào)登錄了一次
setbit 20190102 3 1
# 編號(hào)為7的用戶在2019年1月2號(hào)登錄了一次
setbit 20190102 7 1
# 編號(hào)為7的用戶在2019年1月3號(hào)登錄了一次
setbit 20190103 7 1
然后通過(guò):
# 將每一天標(biāo)識(shí)的人數(shù)(位置上為1)的數(shù)進(jìn)行與運(yùn)算
bitop or destkey 20190101 20190102 20190103
然后求這個(gè)destkey中含有的1的數(shù)量,即為比較活躍的用戶(派發(fā)禮物需要準(zhǔn)備的禮物數(shù)量)
BITCOUNT destkey
搶購(gòu),秒殺,詳情頁(yè),點(diǎn)贊,評(píng)論
都可以使用Redis的incr 方法,這樣就可以規(guī)避并發(fā)下,對(duì)數(shù)據(jù)庫(kù)的事務(wù)操作,完全由redis內(nèi)存操作代替
更多命令
# lpush和lpop搭配可以實(shí)現(xiàn)棧的功能
# lpush和rpop搭配可以實(shí)現(xiàn)隊(duì)列的功能
# 從左邊進(jìn)
lpush k1 a b c
# 從左邊彈出
lpop k1
c
# lrange可以從左到右列出元素
lpush k1 a b c
lrange k1
1) "c"
2) "b"
3) "a"
# lindex 可以定位某個(gè)元素(從左邊開(kāi)始,從0開(kāi)始)
lindex k1 0
"c"
# lset 可以設(shè)置某個(gè)位置的元素
lset k1 0 xxxxx
lrange k1 0 -1
1) "xxxxx"
2) "b"
3) "a"
#LREM key count value
#根據(jù)參數(shù) count 的值,移除列表中與參數(shù) value 相等的元素。
#count 的值可以是以下幾種:
#count > 0 : 從表頭開(kāi)始向表尾搜索,移除與 value 相等的元素,數(shù)量為 count 。
#count 0 : 從表尾開(kāi)始向表頭搜索,移除與 value 相等的元素,數(shù)量為 count 的絕對(duì)值。
#count = 0 : 移除表中所有與 value 相等的值。
LREM k3 2 a
# LINSERT
lpush k1 a b c d e f g
linsert k1 after b 6 # 也可以用before
lrange k1 0 -1
1) "g"
2) "f"
3) "e"
4) "d"
5) "c"
6) "b"
7) "6"
8) "a"# lpush和lpop搭配可以實(shí)現(xiàn)棧的功能
# lpush和rpop搭配可以實(shí)現(xiàn)隊(duì)列的功能
# 從左邊進(jìn)
lpush k1 a b c
# 從左邊彈出
lpop k1
c
# lrange可以從左到右列出元素
lpush k1 a b c
lrange k1
1) "c"
2) "b"
3) "a"
# lindex 可以定位某個(gè)元素(從左邊開(kāi)始,從0開(kāi)始)
lindex k1 0
"c"
# lset 可以設(shè)置某個(gè)位置的元素
lset k1 0 xxxxx
lrange k1 0 -1
1) "xxxxx"
2) "b"
3) "a"
#當(dāng) BLPOP被調(diào)用時(shí),如果給定 key 內(nèi)至少有一個(gè)非空列表,那么彈出遇到的第一個(gè)非空列表的頭元素,并和被彈出元素所屬的列表的名字 key 一起,組成結(jié)果返回給調(diào)用者。
# BLPOP可以實(shí)現(xiàn)單播FIFO隊(duì)列
blpop x y z 0
# 打開(kāi)另外一個(gè)redis-cli
# 然后執(zhí)行
lpush y xxxsd
# 可以看到blpop x y z 0
# 返回了參數(shù)
blpop x y z 0
1) "y"
2) "xxxsd"
# blpop 最后一個(gè)參數(shù)是超時(shí)時(shí)間,如果設(shè)置為0,則不超時(shí)
# trim掉第三號(hào)元素之前和第五號(hào)元素之后的元素,從左邊第0個(gè)位置開(kāi)始算
lpush k1 a b c d e f g
(integer) 15
ltrim k1 1 3
OK
lrange k1 0 -1
1) "f"
2) "e"
3) "d"
# Hash
hset person name zs
(integer) 1
hset person age 18 address GZ
(integer) 2
hmget person name age address
1) "zs"
2) "18"
3) "GZ"
hkeys person
1) "name"
2) "age"
3) "address"
hvals person
1) "zs"
2) "18"
3) "GZ"
hgetall person
1) "name"
2) "zs"
3) "age"
4) "18"
5) "address"
6) "GZ"
hincrbyfloat person age 0.5
"18.5"
hincrbyfloat person age -1
"17.5"
sadd k1 a b c a
(integer) 3
smembers k1
1) "b"
2) "a"
3) "c"
srem k1 a
(integer) 1
smembers k1
1) "b"
2) "c"
# 交集sinter,類似的,還有并集:sunion,差集:sdiff
# sinerstore k k1 k2 將k1和k2交集后的元素存入k
sadd k1 a b c
SMEMBERS k1
1) "a"
2) "c"
3) "b"
sadd k2 a b d
(integer) 3
SINTER k1 k2
1) "a"
2) "b"
SUNION k1 k2
1) "a"
2) "d"
3) "b"
4) "c"
SDIFF k1 k2
"c"
#SRANDMEMBER 命令接受可選的 count 參數(shù):
#如果 count 為正數(shù),且小于集合基數(shù),那么命令返回一個(gè)包含 count 個(gè)元素的數(shù)組,數(shù)組中的元素各不相同。如果 count 大于等于集合基數(shù),那么返回整個(gè)集合。
#如果 count 為負(fù)數(shù),那么命令返回一個(gè)數(shù)組,數(shù)組中的元素可能會(huì)重復(fù)出現(xiàn)多次,而數(shù)組的長(zhǎng)度為 count 的絕對(duì)值。
# 可以用來(lái)抽獎(jiǎng)
SRANDMEMBER k3 -3
1) "b"
2) "b"
3) "c"
#有序集
#sorted_set
#Z開(kāi)頭的命令,ZADD,ZCOUNT
zadd fruit 8 apple 2 banana 3 orange
zrange fruit 0 -1
1) "banana"
2) "orange"
3) "apple"
zrange fruit 0 -1 withscores
1) "banana"
2) "2"
3) "orange"
4) "3"
5) "apple"
6) "8"
zcount fruit 3 8
(integer) 2
zscore fruit apple
"8"
#價(jià)格由低到高取出前兩位
zarange k1 0 1
#價(jià)格由高到低取出前兩位
zrevarange k1 0 1
zscore fruit apple
"8"
zrank fruit banana
0
zincrby fruit 2.5 banana
"4.5"
127.0.0.1:6379> zadd k1 2 a 3 b 4 c
(integer) 3
127.0.0.1:6379> zadd k2 3 a 1 b 2 c
(integer) 3
127.0.0.1:6379> ZUNIONSTORE k4 2 k1 k2
(integer) 3
127.0.0.1:6379> zrange k4 0 -1
1) "b"
2) "a"
3) "c"
127.0.0.1:6379> ZUNIONSTORE k4 2 k1 k2 aggregate sum
(integer) 3
127.0.0.1:6379> zrange k4 0 -1
1) "b"
2) "a"
3) "c"
127.0.0.1:6379> ZUNIONSTORE k4 2 k1 k2 aggregate max
(integer) 3
127.0.0.1:6379> zrange k4 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> ZUNIONSTORE k4 2 k1 k2 aggregate min
(integer) 3
127.0.0.1:6379> zrange k4 0 -1
1) "b"
2) "a"
3) "c"
通過(guò)管道連接Redis發(fā)送命令
yum install nc
[root@node01 ~]# nc localhost 6379
keys *
*0
set k1 heelo
+OK
[root@node1 utils]# echo -e "set k2 99\nincr k2\n get k2" | nc localhost 6379
+OK
:100
$3
100
發(fā)布/訂閱功能
127.0.0.1:6379> subscribe xxx
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "xxx"
3) (integer) 1
1) "message"
2) "xxx"
3) "hellod"
127.0.0.1:6379> publish xxx hellod
(integer) 1
如果需要考慮獲取實(shí)時(shí)數(shù)據(jù)和歷史數(shù)據(jù)
關(guān)于實(shí)時(shí)數(shù)據(jù)
- pub/sub功能關(guān)于歷史消息
- 三天前(sorted_set)
- 更早以前(來(lái)自數(shù)據(jù)庫(kù))
架構(gòu)如下:
Redis的事務(wù)
執(zhí)行順序
示例
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set k1 aa
QUEUED
127.0.0.1:6379(TX)> set k2 ddd
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
watch用法
127.0.0.1:6379> watch k1
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> keys *
QUEUED
127.0.0.1:6379(TX)> exec
(nil)
另外一個(gè)客戶端
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> keys *
QUEUED
127.0.0.1:6379(TX)> set k1 ddsdfasdf
QUEUED
127.0.0.1:6379(TX)> exec
1) (empty array)
2) OK
為什么 Redis 的事務(wù)不支持回滾(roll back)
摘自:http://www.redis.cn/topics/transactions.html
如果你有使用關(guān)系式數(shù)據(jù)庫(kù)的經(jīng)驗(yàn), 那么 “Redis 在事務(wù)失敗時(shí)不進(jìn)行回滾,而是繼續(xù)執(zhí)行余下的命令”這種做法可能會(huì)讓你覺(jué)得有點(diǎn)奇怪。
以下是這種做法的優(yōu)點(diǎn):
Redis 命令只會(huì)因?yàn)殄e(cuò)誤的語(yǔ)法而失?。ú⑶疫@些問(wèn)題不能在入隊(duì)時(shí)發(fā)現(xiàn)),或是命令用在了錯(cuò)誤類型的鍵上面:這也就是說(shuō),從實(shí)用性的角度來(lái)說(shuō),失敗的命令是由編程錯(cuò)誤造成的,而這些錯(cuò)誤應(yīng)該在開(kāi)發(fā)的過(guò)程中被發(fā)現(xiàn),而不應(yīng)該出現(xiàn)在生產(chǎn)環(huán)境中。因?yàn)椴恍枰獙?duì)回滾進(jìn)行支持,所以 Redis 的內(nèi)部可以保持簡(jiǎn)單且快速。有種觀點(diǎn)認(rèn)為 Redis 處理事務(wù)的做法會(huì)產(chǎn)生 bug , 然而需要注意的是, 在通常情況下, 回滾并不能解決編程錯(cuò)誤帶來(lái)的問(wèn)題。 舉個(gè)例子, 如果你本來(lái)想通過(guò) INCR 命令將鍵的值加上 1 , 卻不小心加上了 2 , 又或者對(duì)錯(cuò)誤類型的鍵執(zhí)行了 INCR , 回滾是沒(méi)有辦法處理這些情況的。
以上就是詳解Redis基本命令與使用場(chǎng)景的詳細(xì)內(nèi)容,更多關(guān)于Redis基本命令與使用場(chǎng)景的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- redis的五大數(shù)據(jù)類型應(yīng)用場(chǎng)景分析
- 解析redis hash應(yīng)用場(chǎng)景和常用命令
- 了解Redis常見(jiàn)應(yīng)用場(chǎng)景
- 淺談Redis在直播場(chǎng)景的實(shí)踐方案
- SpringBoot集成Redisson實(shí)現(xiàn)延遲隊(duì)列的場(chǎng)景分析
- 淺談redis五大數(shù)據(jù)結(jié)構(gòu)和使用場(chǎng)景
- 詳解redis中的鎖以及使用場(chǎng)景
- Redis的11種Web應(yīng)用場(chǎng)景簡(jiǎn)介
- Redis 常見(jiàn)使用場(chǎng)景