天天看點

Python Redis

  NoSQL(NoSQL = Not Only SQL ),意即“不僅僅是SQL”,是一項全新的資料庫革命性運動,泛指非關系型的資料庫。随着網際網路web2.0網站的興起,傳統的關系資料庫在應付web2.0網站,特别是超大規模和高并發的SNS類型的web2.0純動态網站已經顯得力不從心,暴露了很多難以克服的問題,而非關系型的資料庫則由于其本身的特點得到了非常迅速的發展。NoSQL資料庫的産生就是為了解決大規模資料集合多重資料種類帶來的挑戰,尤其是大資料應用難題。

  NoSQL四個大分類:

  鍵值(Key-Value)存儲資料庫:這一類資料庫主要會使用到一個哈希表,這個表中有一個特定的鍵和一個指針指向特定的資料。Key/value模型對于IT系統來說的優勢在于簡單、易部署。但是如果DBA隻對部分值進行查詢或更新的時候,Key/value就顯得效率低下了。舉例如:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB。

  列存儲資料庫:這部分資料庫通常是用來應對分布式存儲的海量資料。鍵仍然存在,但是它們的特點是指向了多個列。這些列是由列家族來安排的。如:Cassandra, HBase, Riak.

  文檔型資料庫:文檔型資料庫的靈感是來自于Lotus Notes辦公軟體的,而且它同第一種鍵值存儲相類似。該類型的資料模型是版本化的文檔,半結構化的文檔以特定的格式存儲,比如JSON。文檔型資料庫可 以看作是鍵值資料庫的更新版,允許之間嵌套鍵值。而且文檔型資料庫比鍵值資料庫的查詢效率更高。如:CouchDB, MongoDb. 國内也有文檔型資料庫SequoiaDB,已經開源。

  圖形(Graph)資料庫:圖形結構的資料庫同其他行列以及剛性結構的SQL資料庫不同,它是使用靈活的圖形模型,并且能夠擴充到多個伺服器上。NoSQL資料庫沒有标準的查詢語言(SQL),是以進行資料庫查詢需要制定資料模型。許多NoSQL資料庫都有REST式的資料接口或者查詢API。如:Neo4J, InfoGrid, Infinite Graph.

  NoSQL資料庫使用場景:

  1、資料模型比較簡單;

  2、需要靈活性更強的IT系統;

  3、對資料庫性能要求較高;

  4、不需要高度的資料一緻性;

  5、對于給定key,比較容易映射複雜值的環境。

鍵值(key-value) Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB 内容緩存,主要用于處理大量資料的高通路負載,也用于一些日志系統等等。 Key 指向 Value 的鍵值對,通常用hash table來實作 查找速度快 資料無結構化,通常隻被當作字元串或者二進制資料
列存儲資料庫 Cassandra, HBase, Riak 分布式的檔案系統 以列簇式存儲,将同一列資料存在一起 查找速度快,可擴充性強,更容易進行分布式擴充 功能相對局限
文檔型資料庫 CouchDB, MongoDb Web應用(與Key-Value類似,Value是結構化的,不同的是資料庫能夠了解Value的内容) Key-Value對應的鍵值對,Value為結構化資料 資料結構要求不嚴格,表結構可變,不需要像關系型資料庫一樣需要預先定義表結構 查詢性能不高,而且缺乏統一的查詢文法。
圖形(Graph)資料庫 Neo4J, InfoGrid, Infinite Graph 社交網絡,推薦系統等。專注于建構關系圖譜 圖結構 利用圖結構相關算法。比如最短路徑尋址,N度關系查找等 很多時候需要對整個圖做計算才能得出需要的資訊,而且這種結構不太好做分布式的叢集方案

對于NoSQL并沒有一個明确的範圍和定義,但是他們都普遍存在下面一些共同特征:

(1)不需要預定義模式:不需要事先定義資料模式,預定義表結構。資料中的每條記錄都可能有不同的屬性和格式。當插入資料時,并不需要預先定義它們的模式。

(2)無共享架構:相對于将所有資料存儲的存儲區域網絡中的全共享架構。NoSQL往往将資料劃分後存儲在各個本地伺服器上。因為從本地磁盤讀取資料的性能往往好于通過網絡傳輸讀取資料的性能,進而提高了系統的性能。

(3)彈性可擴充:可以在系統運作的時候,動态增加或者删除結點。不需要停機維護,資料可以自動遷移。

(4)分區:相對于将資料存放于同一個節點,NoSQL資料庫需要将資料進行分區,将記錄分散在多個節點上面。并且通常分區的同時還要做複制。這樣既提高了并行性能,又能保證沒有單點失效的問題。

(5)異步複制:和RAID存儲系統不同的是,NoSQL中的複制,往往是基于日志的異步複制。這樣,資料就可以盡快地寫入一個節點,而不會被網絡傳輸引起遲延。缺點是并不總是能保證一緻性,這樣的方式在出現故障的時候,可能會丢失少量的資料。

(6)BASE:相對于事務嚴格的ACID特性,NoSQL資料庫保證的是BASE特性。BASE是最終一緻性和軟事務。

(7)NoSQL資料庫并沒有一個統一的架構,兩種NoSQL資料庫之間的不同,甚至遠遠超過兩種關系型資料庫的不同。可以說,NoSQL各有所長,成功的NoSQL必然特别适用于某些場合或者某些應用,在這些場合中會遠遠勝過關系型資料庫和其他的NoSQL。

Redis

  Redis是一個key-value存儲系統。和Memcached類似,它支援存儲的value類型相對更多,包括string(字元串)、list(連結清單)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些資料類型都支援push/pop、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支援各種不同方式的排序。與memcached一樣,為了保證效率,資料都是緩存在記憶體中。差別的是redis會周期性的把更新的資料寫入磁盤或者把修改操作寫入追加的記錄檔案,并且在此基礎上實作了master-slave(主從)同步。

  Redis 是一個高性能的key-value資料庫。 redis的出現,很大程度補償了memcached這類key/value存儲的不足,在部 分場合可以對關系資料庫起到很好的補充作用。它提供了Python,Ruby,Erlang,PHP用戶端,使用很友善,Redis支援主從同步。資料可以從主伺服器向任意數量的從伺服器上同步,從伺服器可以是關聯其他從伺服器的主伺服器。這使得Redis可執行單層樹複制。從盤可以有意無意的對資料進行寫操作。由于完全實作了釋出/訂閱機制,使得從資料庫在任何地方同步樹時,可訂閱一個頻道并接收主伺服器完整的消息釋出記錄。

#Redis常用shell
[root@localhost ~]# redis-cli      # 進入redis cli視窗
127.0.0.1:6379> set name fgf     # 設定值
OK
127.0.0.1:6379> set age 02
OK
127.0.0.1:6379> keys *              # 目前所有key
1) "age"
2) "name"
127.0.0.1:6379> set sex m ex 2      # 設定值,隻存活2秒
OK
127.0.0.1:6379> get sex       # 擷取值
"m"
127.0.0.1:6379> flushdb      # 清空目前db下的所有鍵值
OK
127.0.0.1:6379> flushall      # 清空所有db下的鍵值
OK           

複制

Python操作Redis

1)操作模式

  redis-py提供兩個類Redis和StrictRedis用于實作Redis的指令,StrictRedis用于實作大部分官方的指令,并使用官方的文法和指令,Redis是StrictRedis的子類,用于向後相容舊版本的redis-py。

import redis
r = redis.Redis(host='127.0.0.1', port=6379)
r.set('foo', 'Bar')       #添加
print (r.get('foo'))      #擷取           

複制

2)連接配接池

  redis-py使用connection pool來管理對一個redis server的所有連接配接,避免每次建立、釋放連接配接的開銷。預設,每個Redis執行個體都會維護一個自己的連接配接池。可以直接建立一個連接配接池,然後作為參數Redis,這樣就可以實作多個Redis執行個體共享一個連接配接池。

import redis
pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
r = redis.Redis(connection_pool=pool)
r.set('foo', 'Bar')     #添加
print r.get('foo')      #擷取           

複制

3)管道

  redis-py預設在執行每次請求都會建立(連接配接池申請連接配接)和斷開(歸還連接配接池)一次連接配接操作,如果想要在一次請求中指定多個指令,則可以使用pipline實作一次請求指定多個指令,并且預設情況下一次pipline 是原子性操作。

import redis
pool = redis.ConnectionPool(host='192.168.0.110', port=6379)
r = redis.Redis(connection_pool=pool)
pipe = r.pipeline(transaction=True)
r.set('name', 'zhangsan')
r.set('name', 'lisi')
pipe.execute()           

複制

1、字元串操作

  redis中的String在在記憶體中按照一個name對應一個value來存儲

#在Redis中設定值,預設不存在則建立,存在則修改r.('name', 'zhangsan')'''參數:
     set(name, value, ex=None, px=None, nx=False, xx=False)
     ex,過期時間(秒)
     px,過期時間(毫秒)
     nx,如果設定為True,則隻有name不存在時,目前set操作才執行,同setnx(name, value)
     xx,如果設定為True,則隻有name存在時,目前set操作才執行'''
#設定過期時間(秒)
setex(name, value, time)
#設定過期時間(豪秒)
psetex(name, time_ms, value)
#批量設定值
r.mset(name1='zhangsan', name2='lisi')
#或
r.mget({"name1":'zhangsan', "name2":'lisi'})
#批量擷取
print(r.mget("name1","name2"))
#或
li=["name1","name2"]
print(r.mget(li))
#設定新值,列印原值
print(r.getset("name1","wangwu"))     #輸出:zhangsan
print(r.get("name1"))                 #輸出:wangwu
#根據位元組擷取子序列
r.set("name","zhangsan")
print(r.getrange("name",0,3))         #輸出:zhan
#修改字元串内容,從指定字元串索引開始向後替換,如果新值太長時,則向後添加
r.set("name","zhangsan")
r.setrange("name",1,"z")
print(r.get("name"))                  #輸出:zzangsan
r.setrange("name",6,"zzzzzzz")
print(r.get("name"))                  #輸出:zzangszzzzzzz           

複制

2、List操作

  redis中的List在在記憶體中按照一個name對應一個List來存儲 

# 在name對應的list中添加元素,每個新的元素都添加到清單的最左邊
r.lpush("list_name",2)
r.lpush("list_name",3,4,5)      #儲存在清單中的順序為5,4,3,2
#同lpush,但每個新的元素都添加到清單的最右邊
rpush(name,values)
#在name對應的list中添加元素,隻有name已經存在時,值添加到清單的最左邊
lpushx(name,value)
#在name對應的list中添加元素,隻有name已經存在時,值添加到清單的最右邊
rpushx(name,value)
# name對應的list元素的個數
print(r.llen("list_name"))
# 在name對應的清單的某一個值前或後插入一個新值
r.linsert("list_name","BEFORE","2","SS")   #在清單内找到第一個元素2,在它前面插入SS
'''參數:
     name: redis的name
     where: BEFORE(前)或AFTER(後)
     refvalue: 清單内的值
     value: 要插入的資料'''
#對list中的某一個索引位置重新指派
r.lset("list_name",0,"bbb")
#删除name對應的list中的指定值
r.lrem("list_name","SS",num=0)
''' 參數:
    name:  redis的name
    value: 要删除的值
    num:   num=0 删除清單中所有的指定值;
           num=2 從前到後,删除2個;
           num=-2 從後向前,删除2個'''
#移除清單的左側第一個元素,傳回值則是第一個元素
print(r.lpop("list_name"))
#根據索引擷取清單内元素
print(r.lindex("list_name",1))
#分片擷取元素
print(r.lrange("list_name",0,-1))
#移除清單内沒有在該索引之内的值
r.ltrim("list_name",0,2)           

複制

3、Set操作

#給name對應的集合中添加元素
r.sadd("set_name","aa")
r.sadd("set_name","aa","bb")
# 擷取多個name對應集合的并集
r.sadd("set_name","aa","bb")
r.sadd("set_name1","bb","cc")
r.sadd("set_name2","bb","cc","dd")
print(r.sinter("set_name","set_name1","set_name2"))       #輸出:{bb}
#擷取name對應的集合的所有成員
smembers(name)
#擷取name對應的集合中的元素個數
r.scard("set_name")
# 在name對應的有序集合中添加元素
r.zadd("zset_name", "a1", 6, "a2", 2,"a3",5)
#或r.zadd('zset_name1', b1=10, b2=5)
#擷取有序集合中分數在[min,max]之間的個數
print(r.zcount("zset_name",1,5))
#自增有序集合内value對應的分數
r.zincrby("zset_name","a1",amount=2)      #自增zset_name對應的有序集合裡a1對應的分數           

複制

其他常用操作:

delete(*names)          #根據name删除redis中的任意資料類型

exists(name)             #檢測redis的name是否存在

keys(pattern='*')      #根據* ?等通配符比對擷取redis的name

expire(name ,time)   # 為某個name設定逾時時間

rename(src, dst)      # 重命名

move(name, db))    # 将redis的某個值移動到指定的db下

randomkey()          #随機擷取一個redis的name(不删除)

type(name)           # 擷取name對應值的類型