-
set 設置值
R: set name lin
P: redis.set('name', 'lin')
set選項(原子操做)
nx(設置默認值)
R: set name lin nx
P: redis.set('name', 'lin', nx=True)
注: nx 表明key不存在纔會將值設置成功, 相似python dict的 setdefault,即給key設置默認值
xx(更新值)
R: set name Tom xx
P: redis.set('name', 'lin', xx=True)
注: xx 表明key存在纔會將值更新成功。 若是key不存在, 則更新失敗。
-
get 獲取值
R: get name
P: redis.get('name')
注:經過py redis客戶端的 get取出的都是 字節二進制類型, 因此須要手動轉爲對應類型
前面提到的 incr decr 等, 操做返回結果直接就是 int, 而非 字節類型
-
mset 批量設置
R: mset name lin age 18
p: redis.mset( {'name': 'lin', 'age': 18} )
-
mget 批量獲取
R: mget name age
p: redis.mget('name', 'age') # 返回值爲 字節類型的 列表
-
getset 設置新值並返回舊值
R: getset name zhang
P: print( redis.getset('name', 'zhang') )
-
append 字符串追加拼接
R: append name abc
P: redis.append('name', 'abc')
-
strlen 獲取字符串長度
R: strlen name
P: print( redis.strlen('name') )
注: 與編程語言的廣泛API不一樣的是, strlen返回的字符串 長度是 字符對應編碼的長度。。。。
中文 utf-8 佔 3個字節
-
getrange 字符串切片 (從0開始,前閉後閉)
R: getrange name 1 2
P: redis.getrange('name', 1, 2)
-
setrange 字符串按索引賦值(覆蓋)
R: setrange name 0 abc # 把第0個位置開始, 逐個覆蓋賦值爲 abc, 多餘的不變
P: redis.setrange('name', 0, 'abc')
-
del 刪除鍵值
R: del k1 k2
P: redis.delete(k1, k2)
-
hset 設置 1條文檔,1個屬性-值
R: hset user name lin
P: redis.hset('user', 'name', 'lin')
-
hget 獲取 1條文檔,1個屬性
R: hget user name
P: print(redis.hget('user', 'name'))
-
hmset 設置 1條文檔, 多個屬性-值
R: hmset user name lin age 18
P: redis.hmset('user', {'user': 'lin', 'age': 18})
-
hmget 獲取 1條文檔, 多個屬性-值
R: hmget user name age
P: print(redis.hmget('user', 'name', 'age'))
-
hkeys 獲取全部 key
R: hkeys user
P: print(redis.hkeys('user'))
-
hvals 獲取全部 values
R: hvals user
P: print(redis.hvals('user'))
-
hgetall 獲取 一條文檔,全部屬性值(慎用,見下一條API)
R: hgetall user # 返回爲列表, 偶數索引爲key,奇數索引爲vaLue(從0開始)
P: print(redis.hgetall('user')) # 返回爲 dict格式
注: hgetall 會將全部key-value取出來,因此數據量龐大可能會形成性能影響。
大批量數據在python是怎麼處理來着???????
沒錯,就是迭代器,固然python的redis模塊已爲咱們封裝好一個API,hscan_iter, 見一條API
-
hscan (hash迭代,大致上可代替 hgetall使用)
R: hscan user 0 match * count 200 # 按遊標,按數量取
# 0表明遊標從頭開始
# match是關鍵字
# * 是key的通配符
# count 是一次接待的條數
P: result_iter = redis.hscan_iter('user', match= 'na*', count=2)
# python的 cursor參數沒有,是由於源碼中被固定設置爲 0了, 其餘參數解釋同上
# 返回結果爲可迭代對象,可遍歷取出。
-
hexists 檢測是否存在某key
R: hexists user name1 # 存在返回 1,不存在返回 0
P: print(redis.hexists('user', 'name')) # 存在返回True
-
hlen 統計獲取一個文檔,全部屬性的 總數
R: hlen user
P: print(redis.hlen('user'))
-
hdel 刪除指定字段
R: hdel key field
P: redis.hdel('key', 'field')
-
lpush (左壓棧)
R: lpush list1 1 2 3
P: redis.lpush('list1', 1,2,3)
rpush (右壓棧,同左壓棧,略)
-
lpop (左彈棧)
R: lpop list2
P: print(redis.lpop('list2'))
rpop (右彈棧,同左彈棧,略)
-
blpop (左阻塞彈棧,列表爲空時,就阻塞了)
R: blpop list2 1000 # 1000爲過時時間爲1000秒,1000秒後自動解除阻塞,有值加入也會解除阻塞
P: redis.blpop('list2', timeout=1000)
brpop (右阻塞彈棧,同左阻塞彈棧,略)
-
linsert ( 在指定 值 的 先後 插入值)
R: linsert list2 before Tom jerry # 在Tom前插入 jerry, before表明以前
P: redis.linsert('list2', 'after', 'b', 'Tom') # 在b的後面插入Tom, after表明以後
-
lset (按索引賦值, 注意索引不要越界)
R:lset list2 4 zhang
P: redis.lset('list2', 4, 'zhang')
-
lindex (按索引取值, 索引可正可負)
R: lindex list2 -3
P: print(redis.lindex('list2', 3))
-
llen (獲取列表元素個數)
R: llen list2
P: print(redis.llen('list2'))
-
ltrim (注意:在原數據上切片,不返回值。)
R: ltrim list2 3 10 # 保留 索引 3-10 的列表數據,其餘都刪除
P: print(redis.ltrim('list2', 2, -1)) # 索引前閉後閉,可正可負
-
lrem (刪除指定值)
R: lrem list2 0 Tom
# 0 這個位置的參數表明刪除值的個數
# 0 表明所有刪除, 刪除所有Tom值
# 正數表明 從左到右 刪除n個。 eg: lrem list2 5 Tom 即爲 從左到右 刪除5個Tom值
# 負數表明 從右到左 刪除n個。 eg: lrem list2 -5 Tom 即爲 從右到左 刪除5個Tom值
P: print(redis.lrem('list2', -5, 1)) # 解釋同上
-
lrange(遍歷,正負索引均可,前閉後閉)
R: lrange list1 0 -1
P: print(redis.lrange('list2', 0, -1))
-
sadd (插入元素)
R: sadd set1 1 2 3
P: redis.sadd('set1', *[1,2,3])
-
srem (刪除指定值的元素)
R: srem set1 Tom
P: redis.srem('set1', 'Tom')
-
scard (獲取集合中元素個數)
R: scard set1
P: redis.scard('set1')
-
sismember (判斷某元素是否在集合)
R: sismember set1 Tom
P: redis.sismember('set1', 'Tom')
-
srandmember (隨機取出集合指定個數元素)
「」「相似py的 random.choices,注意有s」「
R: srandmember set1 2 # 從集合隨機中取出2個元素
P: redis.srandmember('set1', 2)
-
smembers (取出集合中全部元素)
R: smembers set1
P: redis.smembers('set1')
注: 同 hgetall, 若是一次性取出,可能會出問題,因此須要迭代獲取,見下 sscan
-
sscan (遊標/迭代取出集合全部元素)
R: sscan set1 0 match * count 200
P: result_iter = redis.sscan_iter('set1', match='*', count=200) # 遍歷迭代
-
sdiff (差集)
R: sdiff sset1 sset2
P: print(redis.sdiff('sset1', 'sset2'))
-
sinter(交集)
R: sinter sset1 sset2
P: print(redis.sinter('sset1', 'sset2'))
-
sunion (並集)
R: sunion sset1 sset2
P: print(redis.sunion('sset1', 'sset2'))
-
zadd (有序插入)
R: zadd zset 100 Tom 90 Jerry # 100是權重,Tom是數據值, 注意redis-cli 權重在前,值在後
P: redis.zadd('zset', {'Tom': 100, 'Jerry': 90}) # 注意,py語法,權重做爲字典的value
注特別注意:
zadd的默認機制是同值,不一樣權重時,會更新值的權重
eg: 上面再插入一條 Tom, 不過此次的權重是 50 ( zadd zset 50 Tom),則Tom的權重會更新爲50
這時就延申出2個參數,(應該還記得前面講的 set的 nx 和 xx參數吧,沒錯 zadd也有)
nx: (不存在才更新(添加), 存在則更新(添加) 失敗)
R: zadd zset nx 1000 Tom
P: redis.zadd('zset',{'Tom': 1000}, nx=True)
注:
若是Tom這個值以前存在,則這個1000就不會被更新了
若不存在,則就會新建立,並把這個1000設置成功
nx:(存在才更新(添加), 不存在則更新(添加) 失敗)
R: zadd zset xx 1000 Tom
P:redis.zadd('zset',{'Tom': 1000}, xx=True)
注:
若是Tom這個值以前存在,則1000纔會更新成功
若是不存在,好比 {'張三':500}, 張三原本就不存在,用了xx, 他不會被添加進來,更何談更新
-
zrange (遍歷)
R: zrange zset 0 -1
P: print(redis.zrange('zset', 0, -1)) # 返回值爲列表
withscores 參數(把權重也帶出來返回):
R: zrange zset 0 -1 withscores # 注意, 返回時 奇數位 是值, 偶數位是權重
P: print(redis.zrange('zset', 0, -1, withscores=True)) # 返回列表嵌套元組,[(值,權重)]
-
zrevrange (逆序-降序,遍歷)
這條API就是多了 "rev" 三個字母, reversed單詞 熟悉把, python內置逆序高階函數。。就是那個意思
操做同zrange,略
-
zrangebyscore (根據權重來遍歷)
R: zrangebyscore zset 40 99 limit 1 3 # 查出權重在40-99以內的數據,並從第1條開始,返回3條
# 40-99都是閉區間, 要想變成開區間這樣寫便可 (40 (99
P: print(redis.zrangebyscore('zset', 40, 99, start=1, num=3))
-
zrevrangebyscore (根據權重來 逆序遍歷)
操做同 zrangebyscore, 略
這API設計的,還不如,直接弄成一條命令,而後加一個逆序參數,吐槽!!!!
-
zrem (刪除某值)
R: zrem zset Tom # 刪除Tom這個值
P: print(redis.zrem('zset','Tom'))
-
zremrangebyscore (刪除 權重 範圍內的值)
R: zremrangebyscore zset 70 90 # 把權重在70-90分的全部數據刪除
P: redis.zremrangebyscore('zset', 70, 90)
-
zremrangebyrank (刪除 索引 範圍內的值)
R: zremrangebyrank zset 0 -1 # 刪除全部值 ( 0到-1的索引就表明全部值啦!)
P: redis.zremrangebyrank('zset', 0, -1) # redis的API風格真的。。。沒辦法python也無奈同名
-
zcard (獲取有序集合的 全部 元素個數)
R: zcard zset
P: print(redis.zcard('zset'))
-
zcount (統計有序集合的 某權重範圍的 元素個數)
R: zcount zset 10 69 # 一樣默認閉區間, ( 可改成開區間
P: print(redis.zcount('zset',50, 69))
-
zrank (獲取某元素的索引)
R: zrank zset Jerry # 不用猜,索引確定從0開始
P: print(redis.zrank('zset', 'Jerry'))
-
zrevrank (逆序 獲取某元素的索引)
逆序獲取索引,好比最後一個,索引就是0
具體操做,同 zrank, 略
-
zscore (獲取某元素對應的權重)
R: zscore zset Jerry
P: print(redis.zscore('zset', 'Jerry'))
-
zscan (迭代方式和返回 全部元素及其權重)
"""
嗯?似曾相識燕歸來?
前面說過的 scan hsacn sscan 還有接下來要說的 zscan 都是一個樣子的,都是爲了應對大數據來迭代處理
python版的redis給了咱們一個簡化函數,那就是 _iter結尾的, eg: hscan_iter()
這種 _iter結尾的函數,不用咱們來傳遊標cursor參數, 爲啥呢??
一. 由於python有生成器-迭代器機制阿!(固然 _iter等函數的源碼就是用yield爲咱們實現的)
二. cursor遊標不易於管理
"""
R: zscan zset 0 match * count 5
P: zset_iter = redis.zscan_iter('zset', match='*', count=5) # 同理返回可迭代對象
注:還要說明一下:
match參數:
過濾查詢數據(其實過濾完了,數據量小了也不必用scan了,此參數主要用在"hscan"之類的)
"所以match參數可不寫", "match='*' 和 不傳是一個效果的。"
count參數:
Py源碼解釋 ``count`` allows for hint the minimum number of returns
意思就是: 這個參數是一次迭代"最少"取5個",但無論怎麼說,最終仍是會取出所有數據!!
-
zpopmax (彈出最大優先級數據對,redis5.+新增)
R: zpopmax zset1 2 # 2表明彈出最大的2對key:score,不寫,默認只彈一對key:score
P: data = redis.zpopmax(zset1, count=None) # 原理同上
zpopmax可等價於下面兩條命令的加起來的效果:
data = redis.zrange(zset1, -1, -1)
zrem(zset1, data)
注:不管count指定幾個或不指定,py返回值爲 [(key, score)] 列表嵌元組這種格式。
-
zpopmin (彈出最小優先級數據對,redis5.+新增)
用法同zpopmax
zpopmax可等價於下面兩條命令的加起來的效果:
data = redis.zrange(zset1, 0, 0) # 就這裏變了,默認升序,故最小值須要從第0條開始彈
zrem(zset1, data)
注:
zpopmax 和 zpopmin 這兩個方法是 redis5.+纔有的。
前面也說了這種方法 = zrange + zrem
很明顯,由原來的多行操做。變成了原子操做。
我想,redis新增這兩條命令,應該正是解決資源競爭的這一問題!!!!!!
-
生成RDB文件 (三種方法)
"""RDB機制就是 觸發生成RDB文件,將Redis數據以二進制形式寫入其中, 觸發方式有以下三種"""
RDB基本配置:
vi /etc/redis/redis.conf
dbfilename dump.rdb # 配置RDB文件名
dir /var/lib/redis # 配置RDB文件存放目錄 (ll 命令查看 dump.rdb是否爲最新時間)
appendonly no # 若爲yes, 會優先按照aof文件來恢復,或不恢復
上述配置,可在下面三種方法實現的時候,自動觸發生成RDB文件。並在redis啓動時恢復RDB文件
-
觸發方式1:save (阻塞)
R: save
P: redis.save()
-
觸發方式2:bgsave (開fork進程,異步,非阻塞)
R: bgsave
P: redis.bgsave()
-
觸發方式3:自動動態生成RDB文件(配置文件)
在上面RDB基本配置基礎上,追加以下配置
vi /etc/redis/redis.conf
save 100 10 # 100秒鐘改變10條數據就會,自動生成RDB文件
-
RDB缺點
大數據耗時,RDB文件寫入影響IO性能。宕機數據不可控
-
生成AOF文件(三種方法)
"""AOF機制就是 每執行一條命令,都會記錄到緩衝區,在根據某種策略刷新到AOF文件中,策略有以下三種"""
AOF基本配置:
vi /etc/redis/redis.conf
appendonly yes # 開關,先要打開
appendfilename "appendonly.aof" # AOF文件名
dir /var/lib/redis # AOF文件目錄(和RDB是同樣的)
-
刷新策略1:always
always 即緩衝區有一條命令,就會刷新追加到AOF文件中 (安全可靠,耗IO)
-
刷新策略2:everysec (默認)
everysec 即每過1秒 就會把緩衝區的命令 刷新追加到AOF文件中
若是就在這一秒鐘宕機,那麼數據就丟失了。。。(1秒不可控)
-
刷新策略3:no
no 即 何時刷新,全聽操做系統本身的 (徹底不可控)
AOF重寫機制 (兩種方法,異步)
-
重寫清潔過程:
如上可知,愈來愈多的命令會追加到AOF中,其中可能會有一些相似
1、鍵值覆蓋:
set name tom
set name jerry
2、超時時間過時
3、多條插入(可用一條命令代替)
如上無用命令,會讓AOF文件變得繁雜。
可經過 AOF重寫策略優化來達到化簡,提升恢復速度等。
-
重寫原理(查找資料 + 我的理解):
1、 開fork子進程 新弄一份AOF文件,它的任務就是把當前redis中的數據從新按照上面的
」重寫清潔過程「 捋一遍,並記錄到這個新AOF文件中
2、 此時主進程能夠正常接受用戶的請求及修改,(這時可能子進程AOF,和數據庫內容不一致,往下看)
3、 其實---第一條開fork的時候,順便也開了一分內存空間A(名爲重寫緩衝區) 用來平行記錄 用戶新請求的命令
4、 當子進程AOF重寫完過後, 會把上面 空間A中 中的數據命令追加到 AOF中(相似斷點複製)
5、 新AOF替代 舊的AOF
打個比方(針對於 2、3、四):
就是,你給我一個任務,我正作着,你又給我不少任務,我固然忙不過來
那這樣,你先拿個清單記錄下來,一會等我忙完了,我們對接一下就行了)
-
重寫方式1:bgrewriteaof
R: bgrewriteaof
P: redis.bgrewriteaof()
-
重寫方式2:配置文件實現自動重寫
在上面AOF基本配置的基礎上,追加以下配置
vi /etc/redis/redis.conf
appendfsync everysec # 就是上面說的三種策略,選一種 always no
auto-aof-rewrite-min-size 64mb # 當AOF文件超過64mb就會自動重寫
auto-aof-rewrite-percentage 100 # 100爲增加率, 每一次的限制大小是以前的100%,也就是二倍
no-appendfsync-on-rewrite yes # yes 就是不把 「重寫緩衝區」 的內容 刷新到 磁盤
注意這個參數:
這就是針對上面 ’重寫原理‘ 中的第三條 中的 內存空間A(重寫緩衝區)
若是這個 重寫緩衝區 不刷新持久化到磁盤中, 要是宕機了,那麼這個緩衝區的數據就會丟失。
丟失多少呢? 據悉(linux中 最多最多 會丟失 30秒的數據)
若是你將其 設置爲 no,那麼 重寫緩衝區 就會像 前面講的 原始AOF同樣地 刷新持久化到硬盤中。
可是你想一想, 若是 重寫緩衝區 和 原始AOF 都作持久化刷新
那麼 它們就會 競爭 IO,性能一定大打折扣,特殊狀況下,還可能 堵塞。
so, 要性能(設爲yes), 要數據完整安全(設爲no), 本身選....