版本:
python 3.5
redis 3.0.1(redis的安裝 pip install redis)
1、連接
import redis
r = redis.Redis(host='192.168.222.129', port='6379', db=0,password=password)
(這里通過本地遠程連接redis的時候,會有一些問題,請見注一)
創建了redis實例后,就可以開始向redis中設置數據了:
2、使用連接池(connection pool)
就像我們在使用線程的時候,會選擇線程池一樣,redis的連接,我們也會選擇使用connection pool來管理對一個redis server的所有連接,
避免每次建議釋放連接的開銷。默認每個redis實例都會維護一個自己的連接池。
當然我們也可以自己創建一個連接池,然后作為參數Redis,這樣就可以實現多個redis實例共享一個連接池。
如下,我們創建了一個線程池,然后創建了兩個redis實例,通過任何一個實例都可以獲取到線程池中的成員。
3、redis常用API
1)String操作
使用格式:r.set(key, value, ex, px, nx, xx)
ex:過期時間(秒)
px:過期時間(毫秒)
nx:如果設置為True,只有在key不存在的時候才能成功執行
xx:如果設置為True,只有在key存在的時候才能成功執行
添加數據:r.set("name","fiona")
獲取數據:r.get("name")
追加數據:r.append("name", " is cute!")
獲取原值並重新賦值:r.getset("name","airo")
刪除數據:r.delete("name")
默認自增1:r.incr("age", count=1) (如果key對應的value不能轉化為數字,會報錯,如果key不存在,會創建該key並賦值為0再執行自增1,可以指定count,就自增count)
增量:r.incrby("age") (同上)
自減1:r.decr("age") (同上)
減量:r.decrby("age") (同上)
批量設置:r.mset({"key1":"value1", "key2":"value2"})
批量獲取:r.mget("key1", "key2")
2)hash
格式:r.hset(name, key, value)
設置數據:r.hset("myhash","name","fiona")
批量設置數據:r.hmset("myhash",{"name":"fiona","age":18})
獲取數據:r.hget("myhash","name")
獲取所有數據:r.hgetall("myhash")
獲取指定成員值:r.hmget("myhash","name","age")
刪除指定成員field:r.hdel("myhash","name")
刪除整個hash key:r.delete("myhash")
增加:r.incrby("myhash","age", amount=1) (同上面string的incrby)
判斷field是否存在:r.exists("myhash","age")
查看成員包含的fields個數:r.hlen("myhash")
查看成員包含的所有field:r.hkeys("myhash")
查看成員包含的所有values:r.hvals("myhash")
3)list
向list左邊/右邊插入數據:r.lpush("mylist","a",'b','c')、r.rpush("mylist",1,2 ,3)
查看list的值:r.lrange("myhash", 0,-1)、r.lrange("mylist",0,-2)
彈出左邊/右邊值:r.lpop("myhash")、r.rpop("mylist")
只有當key存在的時候,才能正確執行:r.lpushx("mylist1","aa")
從左到右刪除指定個數的指定元素:r.lrem("mylist", 2,"a")
從右到左刪除指定個數的指定元素:r.lrem("mylist",-2,'b')
刪除所有的指定元素:r.lrem("mylist",0,'c')
刪除指定key:r.delete("mylist")
替換指定位置的元素:r.lset("mylist", 1, "aaa") 將第二個元素設置為aaa
在某個元素之前/之后插入新的元素:r.linsert("mylist","before/after","aaa",'vvv')
從原列表中彈出最后一個元素並保存到新列表中:r.rpoplpush("mylist", "mylist1")
4)set
添加元素:r.sadd("myset","a",'b')
查看所有元素:r.smembers("myset")
判斷某個元素是否存在集合中:r.sismember("myset","a")
求兩個集合的差集:r.sdiff("myset","myset1")
求兩個集合的差集並將差集保存在新的集合中:r.sdiffstore('newset',"myset","myset1")
求兩個集合的並集:r.sunion("myset","myset1")
求兩個集合的並集並將差集保存在新的集合中:r.sunionstore('newset',"myset","myset1")
求兩個集合的交集:r.sinter("myset","myset1")
求兩個集合的交集並將差集保存在新的集合中:r.sinterstore('newset',"myset","myset1")
求集合中元素的個數:r.scard("myset")
從集合中隨機取出一個元素:r.srandmember("mylist")
5)zset
添加元素:r.zadd("myzset",{"fiona":100,"airo":90})
獲取元素個數:r.zcard("myset")
獲取指定分數間的元素個數:r.zcount("myset",50,100)
獲取指定元素區間個元素個數:r.zlexcount("myset",'[fiona','[airo')
按照元素下標返回指定下標范圍內的元素:r.zrange("myset",0,3, withscores=True)
按照元素下標倒敘返回指定下標范圍內的元素:r.zrevrange("myset",0,-1,withscores=True)
按照元素區間返回指定范圍內的元素:r.zrangebylex("myset",'[fiona','[airo')
按照分數范圍返回指定范圍內的元素:r.zrangebyscore("myset",50,100,withscores=True)
按照分數范圍倒敘返回指定范圍內的元素:r.zrevrangebyscore("myset",'100,50,withscores=True')
給指定的元素增加指定值:r.zincrby("myset",10,'airo')
返回指定元素在集合中對應的的索引:r.zrank("myset",'airo')
返回指定元素在倒敘集合中對應的索引:r.zrevrank("myset",'airo')
刪除指定元素:r.zrem("myset",'age')
刪除指定元素區間的元素:r.zremrangebylex("myset",'[airo','[airo')
刪除指定索引區間的元素:r.zremrangebyrank("myset",0,1)
返回指定元素的分數:r.zscore("myset",'fiona')
獲取兩個有序集合的差集並存入新的有序集合:r.zinterstore("myset2",['myset','myset1'], aggregate='min')
注:aggregate取值為min,max,sum。默認是sum。即新的集合中對相同成員做取小、取大或求和操作
獲取兩個集合的並集並存入到新的有序集合:r.zunionstore("myset3",['myset','myset1'],aggregate='max')
獲取兩個集合交集並存入到新的有序集合中:r.zdiffstore("myset4",['myset','myset1'], aggregate='sum')
4、redis通用API
查看redis中保存的所有key:r.keys("*") 參數為正則表達式
判斷key是否存在:r.exists("myset")
重命名key:r.rename("myset","myset1")
設置key的過期時間:r.expire("myset",10)
查看key的剩余過期時間:r.ttl("myset")
查看key的類型:r.type("myset")
5、redis的兩個特性:
1)多數據庫
可以通過select index命令切換數據庫
2)事務性
redis開啟事物后,所有的命令都將被串行化,事物執行期間,redis不會再為其他客戶端提供任何服務,從而保證事物中的所有命令都被原子化執行。
和關系型數據庫中的原子性不同的是,如果redis事物中的一個命令執行失敗,它后面的其他命令還會繼續執行。
redis中通過multi開啟事物,它后面所有執行命令都將會被存到一個隊列中,直到遇到exec這個命令。
exec相當於關系型數據庫中的提交事務
discard相當於事物回滾
在事物開啟之前,如果客戶端和服務器之間通訊出現故障導致網絡斷開,事物中的所有的語句都將不會被服務器執行
如果故障出現在exec之后,那么這個事物中的所有命令都將會被服務器執行。
如下:
事物演示:
1)我開啟了兩個客戶端連接redis服務,窗口2中set num 1,然后可以在窗口1中獲取,自增后,也可以在窗口1中獲取到變化值
2)在窗口1中使用multi 開啟事物,然后給num自增兩次,這時候去窗口2中查詢num,發現值還是2
3)執行exec,然后再去窗口2中查詢num,發現數據被完成了自增
事物回滾演示:
6、redis持久化
RDB持久化
默認是支持的,指在指定時間間隔將內存中的數據快照寫入磁盤中。
優勢:
1)整個redis數據庫將會只包含一個文件,這對於文件備份是非常好的。
比如我們希望每隔1小時歸檔最近24小時的數據,同時還要每天歸檔一次最近30天的數據,那么可以通過這樣的備份策略,一旦系統出現災難性的故障,我們可以非常容易恢復
2)對於災難恢復而言,RDB是非常不錯的選擇,因為我們可以非常輕松的把一個單獨文件壓縮后再轉移的其他的存儲介質
3)性能最大化。對於redis服務進程而已,在開始持久化的時候,唯一需要做的是,分叉出一些進程,之后再由子進程完成這些持久化操作。這樣就可以極大的避免服務器進程執行IO操作。
相比AOF的操作,如果數據集很大,RDB啟動效率更高
缺點:
1)如果想保證數據的高可用性,即最大限度的避免數據的丟失,RDB不是一個很好的選擇,因為系統可能會在定時持久化之前出現一些宕機的情況,還沒有來得及向硬盤寫的時候,數據就丟失了。
2)由於RDB通過fork分叉的方式,子進程來協助完成持久化操作,所以當數據量很大的時候,可能會導致整個服務器會停止一段時間。
配置:
redis.conf中:
save 900 1:每900秒至少有一個key發生變化,那么它會持久化1次。
save 300 10:每300秒至少有10個key發生變化,它會往硬盤寫一次。
save 60 1000:每60秒,至少有10000個key發生變化,它會持久化一次。
數據的保存名:dump.rdb
數據的保存路徑:./當前文件夾下
AOF持久化
將以日志文件的形式記錄服務器所處理的每一個操作。在redis啟動之初,它會讀取日志中的信息來重新構建數據庫,保證啟動后數據庫中數據的完整性。
優勢:
1)可以帶來更高的安全性,redis提供了三種同步策略:每秒同步(異步的),修改同步(同步持久化,效率最高但是最安全),不同步
2)對於日志的寫入操作采用的是append追加模式,所以即使操作過程中出現宕機的情況,也不會破壞文件的已經存在的內容
如果我們本次寫入只寫入了一半數據,就出現了崩潰的問題,我們可以在redis下次啟動的前,可以通過redis.check.aof工具來解決數據一致性問題。
3)如果日志過大,redis可以自動啟動重寫機制。redis以append模式不斷將數據寫入老的文件中,同時redis還會創建一個新的文件來記錄此期間來產生了哪些修改命令被執行,因此,在進行重寫卻換的時候,可以更好的保證數據的安全性。
4)AOF包含一個包括所有格式清晰,易於理解的日志文件用於記錄所有的修改操作。事實上,我們可以通過這個文件來完成數據的一個重建。
劣勢:
1)對於相同數據集的文件,AOF要比 RDB大一些
2)效率相對RDB要低一些
配置:
默認是沒有開AOF模式的,默認采用的是RDB方式,如果想要使用AOF方式的話,我們需要將appendonly改為yes,然后她會產生一個文件appendonly.aof
這里提供了同步的策略:
appendfsync always:沒修改一次就會同步到磁盤
appendfsync everysecond:每秒鍾同步
appendfsync no:不同步
無持久化
這種方式就相當於緩存
注一:
1)如果遠程連接報錯‘由於目標計算機積極拒絕,無法連接’的錯誤,可能是以下幾個原因導致的:
a)將配置文件中的bind 127.0.0.1 注釋掉,這個限制了只允許本機訪問
b)關閉redis的保護模式(protected-mode),這里的保護模式是指是否允許其他ip的設備訪問redis,如果開啟的話,就是只允許本機訪問了。
c)給redis設置密碼(requirepass)。如果只是Linux本機調試,可以跳過此步,但是如果要開放給外網訪問,就必須給redis設置密碼。
注意:以上的設置都僅僅只是用於基於學習環境,正式的開發生產環境是一定不能這樣子設置的。
上面設置完成后,重啟redis服務,再遠程連接,應該就沒有什么問題了。