Python操做nosql數據庫之redis

1、NoSQL的操做linux

  NoSQL,泛指非關係型的數據庫。隨着互聯網web2.0網站的興起,傳統的關係數據庫在應付web2.0網站,特別是超大規模和高併發的SNS類型的web2.0純動態網站已經顯得力不從心,暴露了不少難以克服的問題,而非關係型的數據庫則因爲其自己的特色獲得了很是迅速的發展。NoSQL數據庫的產生就是爲了解決大規模數據集合多重數據種類帶來的挑戰,尤爲是大數據應用難題。web

  雖然NoSQL的流行與火起來才短短几年的時間,可是不能否認,如今已經開始了第二代運動。儘管早期的堆棧代碼只能算是一種實驗,然而如今的系統已經更加的成熟、穩定。不過如今也面臨着一個嚴酷的事實:技術愈來愈成熟——以致於原來很好的NoSQL數據存儲不得不進行重寫,也有少數人認爲這就是所謂的2.0版本。該工具能夠爲大數據創建快速、可擴展的存儲庫。redis

 

非關係型數據庫和關係型數據庫的差異:數據庫

  非關係型數據庫的優點:1. 性能NOSQL是基於鍵值對的,能夠想象成表中的主鍵和值的對應關係,並且不須要通過SQL層的解析,因此性能很是高。2. 可擴展性一樣也是由於基於鍵值對,數據之間沒有耦合性,因此很是容易水平擴展。緩存

  關係型數據庫的優點:1. 複雜查詢能夠用SQL語句方便的在一個表以及多個表之間作很是複雜的數據查詢。2. 事務支持使得對於安全性能很高的數據訪問要求得以實現。對於這兩類數據庫,對方的優點就是本身的弱勢,反之亦然。可是近年來這兩種數據庫都在向着另一個方向進化。例如:NOSQL數據庫慢慢開始具有SQL數據庫的一些複雜查詢功能的雛形,好比Couchbase的index以及MONGO的複雜查詢。對於事務的支持也能夠用一些系統級的原子操做來實現例如樂觀鎖之類的方法來曲線救國。SQL數據庫也開始慢慢進化,好比HandlerSocker技術的實現,能夠在MYSQL上實現對於SQL層的穿透,用NOSQL的方式訪問數據庫,性能能夠上能夠達到甚至超越NOSQL數據庫。可擴展性上例如Percona Server,能夠實現無中心化的集羣。雖然這兩極都由於各自的弱勢而開始進化出另外一極的一些特性,可是這些特性的增長也會消弱其原本具有的優點,好比Couchbase上的index的增長會逐步下降數據庫的讀寫性能。因此怎樣構建系統的短時間和長期存儲策略,用好他們各自的強項是架構師須要好好考慮的重要問題。安全

2、redis服務搭建服務器

  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存儲的不足,在部 分場合能夠對關係數據庫起到很好的補充做用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端,使用很方便。併發

  Redis支持主從同步。數據能夠從主服務器向任意數量的從服務器上同步,從服務器能夠是關聯其餘從服務器的主服務器。這使得Redis可執行單層樹複製。存盤能夠有意無心的對數據進行寫操做。因爲徹底實現了發佈/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道並接收主服務器完整的消息發佈記錄。同步對讀取操做的可擴展性和數據冗餘頗有幫助。

  Redis的安裝

Redis通常都是安裝在linux系統中,具體安裝步驟以下:

#cd /usr/local/src
#wget http://download.redis.io/releases/redis-3.0.1.tar.gz 
#tar xzf redis-3.0.1.tar.gz 
#cd redis-3.0.1 
#make
#src/redis-server &
檢查redis是否正常啓動
Ps –ef |grep redis
Netstat –lnp |grep 6379

 安裝redis客戶端,在pycharm的terminal中進行安裝

pip install redis

3、redis的簡單操做

  redis是以key-value的形式存儲的,因此咱們在操做的時候。首先咱們將redis所在主機的ip和發佈端口做爲參數實例化了一個對象r,而後執行set('name','I love you!'),這樣咱們就在內存中存儲了一個key爲shang,值爲‘I love you!’的項。咱們能夠理解爲{'shang':'I love you!'},當咱們要讀取的以後,keys()就是得到多有key值。

  1.對redis簡單的操做,代碼以下:

import redis

redis_config = {
    "host":"192.168.203.12",
    "port":6379
}

r = redis.Redis(**redis_config)
r.set("abc","something")
#set操做,第一個參數是key,第二個參數是value
print (r.get("abc"))

結果:something

  2.redis的鏈接池,代碼以下:

# redis鏈接池
def get_redis_connect():
    redis_config = {
        "host":"192.168.203.12",
        "port":6379
    }
    pool = redis.ConnectionPool(**redis_config)
    r = redis.Redis(connection_pool=pool)
    return r

if __name__ == "__main__":
    r = get_redis_connect()
    r.set("name","huangdongju")
    print (r.get("name"))

結果:huangdongju


4、redis管道

  redis-py默認在執行每次請求都會建立(鏈接池申請鏈接)和斷開(歸還鏈接池)一次鏈接操做,若是想要在一次請求中指定多個命令,則可使用pipline實現一次請求指定多個命令,而且默認狀況下一次pipline 是原子性操做。減小功耗

  redis是一個cs模式的tcp server,使用和http相似的請求響應協議。一個client能夠經過一個socket鏈接發起多個請求命令。每一個請求命令發出後client一般會阻塞並等待redis服務處理,redis處理完後請求命令後會將結果經過響應報文返回給client。基本的通訊過程以下:

Client: INCR X

Server: 1

Client: INCR X

Server: 2

Client: INCR X

Server: 3

Client: INCR X

Server: 4

  基本上四個命令須要8個tcp報文才能完成。因爲通訊會有網絡延遲,假如從client和server之間的包傳輸時間須要0.125秒。那麼上面的四個命令8個報文至少會須要1秒才能完成。這樣即便redis每秒能處理100個命令,而咱們的client也只能一秒鐘發出四個命令。這顯示沒有充分利用 redis的處理能力。除了能夠利用mget,mset 之類的單條命令處理多個key的命令外咱們還能夠利用pipeline的方式從client打包多條命令一塊兒發出,不須要等待單條命令的響應返回,而redis服務端會處理完多條命令後會將多條命令的處理結果打包到一塊兒返回給客戶端。通訊過程以下:

Client: INCR X

Client: INCR X

Client: INCR X

Client: INCR X

Server: 1

Server: 2

Server: 3

Server: 4

  假設不會由於tcp報文過長而被拆分。可能兩個tcp報文就能完成四條命令,client能夠將四個命令放到一個tcp報文一塊兒發送,server則能夠將四條命令的處理結果放到一個tcp報文返回。經過pipeline方式當有大批量的操做時候。咱們能夠節省不少原來浪費在網絡延遲的時間。須要注意到是用 pipeline方式打包命令發送,redis必須在處理完全部命令前先緩存起全部命令的處理結果。打包的命令越多,緩存消耗內存也越多。因此並是否是打包的命令越多越好。具體多少合適須要根據具體狀況測試

  代碼以下:

import datetime
import redis


def withpipe(r):
    pipe = r.pipeline(transaction=True)
    for i in xrange(1, 1000):
        key = "test1" +str(i)
        value = "test1" + str(i)
        pipe.set(key, value)
    pipe.execute()


def withoutpipe(r):
    # pipe = r.pipeline(transaction=True)
    for i in xrange(1, 1000):
        key = "test1" + str(i)
        value = "test1" + str(i)
        r.set(key, value)

if __name__ == "__main__":
    pool = redis.ConnectionPool(host="192.168.203.12", port=6379, db=0)
    r1 = redis.Redis(connection_pool=pool)
    r2 = redis.Redis(connection_pool=pool)
    start = datetime.datetime.now()
    # print(start)
    withpipe(r1)
    end = datetime.datetime.now()
    # print((end-start).microseconds)
    # print(end-start)
    t_time = (end - start).microseconds
    print("withpipe time is : {0}".format(t_time))

    start = datetime.datetime.now()
    withoutpipe(r2)
    end = datetime.datetime.now()
    t_time = (end - start).microseconds
    print("withoutpipe time is : {0}".format(t_time))

結果:

withpipe time is : 27000
withoutpipe time is : 372000

 

5、string操做

  redis中的string在內存中都是按照一個key對應一個value來存儲的。如:

r.set(「name」, 「huangdongju」)

  1.set的使用方法:

set(name, value, ex=None, px=None, nx=False, xx=False)

  ex,過時時間(秒)

     px,過時時間(毫秒)

     nx,若是設置爲True,則只有name不存在時,當前set操做才執行,同setnx(name, value)

     xx,若是設置爲True,則只有name存在時,當前set操做才執行'''

  2.get(name)     獲取值

print(r.get("name"))

  3.mset()          批量設置值

r.mset(name1="shang", name2="ling")
r.mset({"name3": "kong", "name4": "gu"})

  4.mget(keys, *args)                    批量獲取值

print(r.mget("name1", "name2", "name3", "name4"))

  程序代碼以下:

import redis
pool = redis.ConnectionPool(host="192.168.203.12",port = 6379,db =0)
r = redis.Redis(connection_pool = pool)

r.set("name","huangdongju")
print (r.keys())
print (r.get("name"))
r.mset(name1="huang",name2="momo")
print (r.mget("name1","name2"))
r.mset({"hello":"world","hi":"nice"})
print (r.keys())
print (r.mget("hello","hi"))

  結果:

 

6、list操做

  redis中的List在在內存中按照一個name對應一個List來存儲。經常使用的方法:

  1.lpush(name,values):在name對應的list中添加元素,每一個新的元素都添加到列表的最左邊

  2.rpush(name,values):同lpush,但每一個新的元素都添加到列表的最右邊

  3.lpushx(name,value):在name對應的list中添加元素,只有name已經存在時,值添加到列表的最左邊

  4.rpushx(name,value):在name對應的list中添加元素,只有name已經存在時,值添加到列表的最右邊

  5.llen(name):name對應的list元素的個數

  6.linsert(name,where,refvalue,value):在name對應的列表的某一個值先後插入一個新值

     參數:

         name,redis的name

                   where,BEFORE或AFTER

         refvalue,標杆值,即:在它先後插入數據

      value,要插入的數據

  

  7.r.lset(name,index,value):對name對應的list中的某一個索引位置從新賦值。

   參數:

                name,redis的name

         index,list的索引位置

      value,要設置的值

  8.r.lrem(name,value,num):在name對應的list中刪除指定的值

   參數:

        name,redis的name

         value,要刪除的值

         num,  num=0,刪除列表中全部的指定值;

              num=2,從前到後,刪除2個;

                   num=-2,從後向前,刪除2個

  9.lpop(name):在name對應的列表的左側獲取第一個元素並在列表中移除,返回值刪除那個元素的值

     10.rpop(name) 表示從右向左操做

  11.lindex(name,index):在name對應的列表中根據索引取列表元素

  12.lrange(name,start,end):在name對應的列表分片獲取數據

  程序代碼以下:

import redis
pool  = redis.ConnectionPool(host="192.168.203.12",port=6379,db=0)
r = redis.Redis(connection_pool=pool)

#lpush 在list的左邊增長一個元素
#rpush 在list的右邊增長一個元素
r.lpush("list1","test1")
r.rpush("list1","huang")
r.lpush("list1", "test2")
r.lpush("list1", "test3")
r.lpush("list1", "test2")
r.lpush("list1", 2, 3, 4)
r.lpush("list1", "test2")
print(r.lrange("list1", 0, -1))

#在中間位置增長一個元素
#linsert(name,where,refvalue,value)
#naem   表明的是list對應的key值
#where  After Before
#refvalue  list中的某個元素
#value   要增長的值
r.linsert("list1","AFTER","test2","hello")
print(r.lrange("list1", 0, -1))
r.lset("list1",2,"world")
#lset  更改某個元素的值
# r.lset(name,index,value)

print (r.lrange("list1",0,-1))
print (r.lindex("list1",2))
# lindex   查看list某個下標的值

  結果:

7、set操做

  set集合就是不重複的列表。經常使用的方法:

  1.sadd(name,values):給name對應的集合中添加元素

  2.smembers(name):獲取name對應的集合的全部成員

  3.scard(name):獲取name對應的集合中的元素個數

  4.sinter(keys, *args):獲取多個name對應集合的並集

  5.sismember(name, value):檢查value是不是name對應的集合內的元素

  6.spop(name):從集合的右側移除一個元素,並將其返回

  7.sunion(keys, *args):獲取多個name對應的集合的並集

  8.srem(name, value)  刪除集合中的某個元素

程序代碼以下:

import redis
pool = redis.ConnectionPool(host="192.168.203.12",port=6379,db=0)
r = redis.Redis(connection_pool=pool)
#r.sadd(name,*args) 增長一個name對應的一個集合
r.sadd("set_name","aa","bb","cc")

#smember  查看集合的全部元素
print(r.smembers("set_name"))

#scard 等同於 list 的len  查看元素的個數
print (r.scard("set_name"))

#srem(name,value) 刪除值爲value的指定集合中的某個元素
r.srem("set_name","aa")

print (r.smembers("set_name"))

r.sadd("set_name1","cc","dd","ee")

#sinter  兩個集合的交集
print(r.sinter("set_name","set_name1"))

#sunion  兩個集合的並集
print (r.sunion("set_name","set_name1"))

結果:

 

8、hash類型操做

  Redis在內存中存儲hash類型是以name對應一個字典形式存儲的,簡單來講就是一個name對應一個字典

  1.hset(name,key,value):name對應的hash中設置一個鍵值對(不存在,則建立;不然,修改)

  參數:

      name:redis的name

      key:key對應的hash中的key

      value:value對應的hash中的value

   注:hsetx(name,key,value),當name對應的hash中不存在當前key則建立(至關於添加)

  2.hget(name,key):在name對應的hash中獲取根據key獲取value

  3.hmset(name,mapping):在name對應的hash中批量設置鍵值對

  參數:

       name:redis的name

       mapping:字典,如{'k1':'v1','k2','v2'}

  4.hmget(name,keys,*args):在name對應的hash中獲取多個key的值

  參數:

      name:redis對應的name

      keys:要獲取key的集合,如:['k1','k2','k3']

      *args:要獲取的key,如:k1,k2,k3

  5.hgetall(name):獲取name對應hash的全部鍵值

  6.hlen(name):得到name對應的hash中的鍵值的個數

  7.hkeys(name):獲取name對應的hash中全部的key的值

  8.hvals(name):獲取name對應的hash中全部的value的值

  9.hexists(name,key):檢查name對應的hash是否存在當前傳入的key

  10.hdel(name,*key):將name對應的hash中指定key的鍵值對刪除

  程序例子以下:

import redis
pool = redis.ConnectionPool(host="192.168.203.12",port=6379,db=0)
r = redis.Redis(connection_pool=pool)

#hash的類型操做就是一個name對應一個字典
#hset   hget  hmset  hmget
r.hset("dict1","hello","world")
print (r.hget("dict1","hello"))
r.hmset("dict1",{"k1":"v1","k2":"v2","k3":"v3"})
print (r.hmget("dict1","k1","k2","hello"))
print (r.hgetall("dict1"))

print (r.hlen("dict1"))
print (r.hkeys("dict1"))
print (r.hvals("dict1"))
print (r.hexists("dict1","hello"))
print (r.hexists("dict1","momo"))
r.hdel("dict1","hello")
print (r.hgetall("dict1"))

  結果:

 

9、其餘操做

  1.delete(*name):根據name刪除redis中任意數據類型

  2.exists(name):檢測redis中的name是否存在

  3.keys(pattern='*'):根據* ?等通配符匹配獲取redis的name

  4.expire(name,time):爲某個name設置超時時間

  5.rename(src,dst):重命名

  6.move(name,db):將redis的某個值移動到指定的db下

  7.type(name):獲取name對應值的類型

相關文章
相關標籤/搜索