<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          新聞推薦實戰(zhàn)(三):Redis基礎(chǔ)

          共 22988字,需瀏覽 46分鐘

           ·

          2022-05-22 13:52

          新聞推薦實戰(zhàn)大綱

          新聞推薦實戰(zhàn)(二):MongoDB基礎(chǔ)

          新聞推薦實戰(zhàn)(一):MySQL基礎(chǔ)

          本文屬于新聞推薦實戰(zhàn)—數(shù)據(jù)層—構(gòu)建物料池之Redis。Redis(Remote Dictionary Server ),即遠程字典服務(wù),是一個開源的使用ANSI C語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫。由于是內(nèi)存數(shù)據(jù)庫,讀寫非常高速,可達10w/s的頻率,所以一般應(yīng)用于數(shù)據(jù)變化快、實時通訊、緩存等。但內(nèi)存數(shù)據(jù)庫通常要考慮機器的內(nèi)存大小。Redis 是完全開源免費的,遵守 BSD 協(xié)議,是一個靈活的高性能 key-value 數(shù)據(jù)結(jié)構(gòu)存儲,可以用來作為數(shù)據(jù)庫、緩存和消息隊列。相比于其他的 key-value 緩存產(chǎn)品有以下三個特點:

          • Redis 支持數(shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保存在磁盤中,重啟的時候可以再次加載到內(nèi)存使用。
          • Redis 不僅支持簡單的 key-value 類型的數(shù)據(jù),同時還提供 list,set,zset,hash 等數(shù)據(jù)結(jié)構(gòu)的存儲。
          • Redis 支持主從復(fù)制,即 master-slave 模式的數(shù)據(jù)備份。


          • 安裝Redis模塊

          • Python連接Redis


          安裝

          本項目是基于Ubuntu環(huán)境進行開發(fā),因此接下來都以Ubuntu的環(huán)境為基礎(chǔ),對于其他開發(fā)環(huán)境,大家可以參考相關(guān)的資料進行學習。

          安裝Redis服務(wù)器:

          sudo?apt-get?install?redis-server

          下載完成的結(jié)果

          啟動Redis服務(wù):

          一般來說,當安裝完成后,Redis服務(wù)器會自動啟動,可以通過以下命令檢查是否啟動成功。(ps:如果Active顯示為 active(running) 狀態(tài):表示redis已在運行,啟動成功)

          service?redis-server?status
          image-20211030164432589

          檢查當前進程,查看redis是否啟動。(ps: 可以看到redis服務(wù)正在監(jiān)聽6379端口)

          ps?-aux|grep?redis-server

          或者進入redis客戶端,與服務(wù)器進行通信,當輸入ping命令,如果返回 PONG 表示Redis已成功安裝。

          redis-cli?

          上面的127.0.0.1 是redis服務(wù)器的 IP 地址,6379 是 Redis 服務(wù)器運行的端口。

          命令

          下面簡單介紹一些常用的Redis命令:

          1、基本操作命令:

          • 啟動Redis

            redis-server?[--daemonize?yes][--port?6379]

            可以通過帶參數(shù)方式來啟動,如果參數(shù)過多,可以使用/etc/redis/redis.conf下面的配置文件來啟動Redis。

            redis-server?/etc/redis/redis.conf
          • 連接Redis

            redis-cli?[-h?host?-p?port?-a?password]

            其中上面參數(shù)默認的是redis-server的默認地址和端口號,password可以在服務(wù)啟動時采用參數(shù)的方式或者配置文件方式都可進行設(shè)置。因此可以通過redis-cli,可以連上我們服務(wù)器端的redis服務(wù)。

          • 停止Redis

            停止Redis有兩種方法,一種是通過 redis-cli 停止,另一種是通過殺掉redis服務(wù)進程

            >?redis-cli?shutdown

            >
            ?kill?redis-pid
          • 切換庫指令

            redis.conf配置中默認16個庫,下標從0~15。進入客服端默認選中第0個庫,可以通過select命令進行切換,index表示庫的小標。

            127.0.0.1:6379>?SELECT?index
          • 刪除當前庫的數(shù)據(jù)

            刪除當前選擇的數(shù)據(jù)庫中的所有數(shù)據(jù),這個命令永遠不會出現(xiàn)失敗。

            127.0.0.1:6379[1]>?FLUSHDB?
          • 刪除所有庫的數(shù)據(jù)

            刪除所有數(shù)據(jù)庫里面的數(shù)據(jù),注意是所有數(shù)據(jù)庫,這個命令永遠不會出現(xiàn)失敗。

            127.0.0.1:6379[1]>?FLUSHALL
          • 查看key的數(shù)量

            查看當前選擇的庫中key的數(shù)量

            127.0.0.1:6379>?DBSIZE

            測試以上命令

            neu@neu:~$?redis-server?--daemonize?yes?--port?6378?--requirepass?123456
            28518:C?26?Oct?20:52:56.389?#?oO0OoO0OoO0Oo?Redis?is?starting?oO0OoO0OoO0Oo
            28518:C?26?Oct?20:52:56.389?#?Redis?version=4.0.9,?bits=64,?commit=00000000,?modified=0,?pid=28518,?just?started
            28518:C?26?Oct?20:52:56.389?#?Configuration?loaded
            neu@neu:~$?redis-cli?-p?6378?-a?123456
            127.0.0.1:6378>?set?name?jiangyou??#?在第0個數(shù)據(jù)庫插入一個值
            OK
            127.0.0.1:6378>?select?1??#?選擇第1個數(shù)據(jù)庫
            OK
            127.0.0.1:6378[1]>?set?age?26????#?在第1個數(shù)據(jù)庫插入一個值
            OK
            127.0.0.1:6378[1]>?DBSIZE?????#?第1個數(shù)據(jù)庫當前的key值數(shù)量
            (integer)?1
            127.0.0.1:6378[1]>?FLUSHDB????#?刪除第1個數(shù)據(jù)庫的所有值
            OK
            127.0.0.1:6378[1]>?DBSIZE?????#?刪除后數(shù)據(jù)庫中沒有值
            (integer)?0
            127.0.0.1:6378[1]>?SELECT?0?????#?切換到第0個數(shù)據(jù)庫
            OK
            127.0.0.1:6378>?DBSIZE??????#?第1個數(shù)據(jù)庫的值存在,因此FLUSHDB只刪除第1個數(shù)據(jù)庫的所有值
            (integer)?1
            127.0.0.1:6378>?SELECT?1????
            OK
            127.0.0.1:6378[1]>?FLUSHALL???#?切換到第1個數(shù)據(jù)庫,使用FLUSHALL刪除所有數(shù)據(jù)庫的值
            OK
            127.0.0.1:6378[1]>?SELECT?0
            OK
            127.0.0.1:6378>?DBSIZE????#?切換到第0個數(shù)據(jù)庫,發(fā)現(xiàn)所有的值已被刪除
            (integer)?0

          2、Key的操作命令:

          該部分指令主要是為了對數(shù)據(jù)庫中的key進行增刪改查等一些列操作,下面主要介紹幾個常用的命令。

          • 查找符合模板的Key

            KEYS?pattern

            該指令查找數(shù)據(jù)庫所有符合pattern的key,其中pattern可以為?、* ?、[abc...]、[a-d]等方式。其中?代表一個任意一個字符,*代表任意0個或多個字符,[abc...]代表只能是[]中的值,[a-d]代表a到d范圍內(nèi)總的值。

            127.0.0.1:6378>?keys?*
            1)?"age"
            2)?"school"
            3)?"home"
            4)?"name"
            127.0.0.1:6378>?keys?*e
            1)?"age"
            2)?"home"
            3)?"name"
            127.0.0.1:6378>?keys?a?e
            1)?"age"
            127.0.0.1:6378>?keys?[a-n][ao]me
            1)?"home"
            2)?"name"
            127.0.0.1:6378>?keys?[a-n][a]me
            1)?"name"
          • 查找存在key的數(shù)量

            EXISTS?key?or?[key…]

            該指令為了查找一個或多個key,返回存在key值的數(shù)量。

            127.0.0.1:6378>?exists?name
            (integer)?1
            127.0.0.1:6378>?exists?name?home?id
            (integer)?2
          • 設(shè)置過期時間

            EXPIRE?key?seconds

            expire 設(shè)置 key 的過期時間,時間過期后,key 會被自動刪除,設(shè)置成功返回1,key不存在返回0。

            ?TTL?key

            ttl 命令以秒為單位返回key的剩余過期時間,如果key不存在返回 -2 ?key 存在但沒有關(guān)聯(lián)超時時間則返回 -1 。

            127.0.0.1:6378>?expire?name?30
            (integer)?1
            127.0.0.1:6378>?ttl?name
            (integer)?26
            127.0.0.1:6378>?ttl?name
            (integer)?-2
            127.0.0.1:6378>?ttl?age
            (integer)?-1
            127.0.0.1:6378>?ttl?id
            (integer)?-2
          • Key所屬類型

            TYPE?key

            type命令以字符串的形式返回存儲在 key 中的值的類型,可返回的類型有:string, list, set, zset,hashstream,如果key值不存在返回none。

            127.0.0.1:6378>?set?key1?"value"
            OK
            127.0.0.1:6378>?lpush?key2?"value"
            (integer)?1
            127.0.0.1:6378>?SADD?key3?"value"
            (integer)?1
            127.0.0.1:6378>?type?key1
            string
            127.0.0.1:6378>?type?key2
            list
            127.0.0.1:6378>?type?key3
            set
            127.0.0.1:6378>?type?key
            none
          • 刪除Key

            DEL?key?or?[key…]

            del命令刪除指定的key,不存在的key忽略,返回0,如果key存在,返回刪除的key的個數(shù)。

            127.0.0.1:6378>?del?key
            (integer)?0
            127.0.0.1:6378>?del?key1?key2
            (integer)?2

          3、字符串類型—string命令:

          字符串是Redis中最常見的數(shù)據(jù)類型,它能夠存儲任何形式的字符串,其中包括二進制格式,JSON格式,序列化格式等數(shù)據(jù)。而string相關(guān)的命令則是用于管理redis字符串值,下面介紹一些常見命令。

          基礎(chǔ)命令

          • SET

            set命令將key定為指定的字符串,如果key存在,則會覆蓋原來的值。

            SET?key?value?[EX?seconds]?[PX?milliseconds]?[NX|XX]

            其中set可以為設(shè)定的值設(shè)置過期時間,EX表示秒數(shù),PX表示毫秒。參數(shù)NX表示只有鍵key不存在的時候才會設(shè)置key的值,XX表示只有鍵key存在的時候才會設(shè)置key的值。

          • GET

            get命令返回與鍵 key 相關(guān)聯(lián)的字符串值。

            GET?key

            如果key不存在,返回nil,如果key的值是非字符串類型,那么返回一個錯誤。

          • APPEND

            append命令將指定的key追加值。如果key存在,并且是字符串,則會將value追加到key原值的末尾,如果key值是非字符串則會報錯,當key不存在時候,改命令類似于set,簡單將key設(shè)定為value。

            APPEND?KEY_NAME?NEW_VALUE
          • INCR

            incr 命令將 key 中儲存的數(shù)字值增一。如果key不存在,key值會被初始化為0,在進行incr操作。如果字符串類型的值不能表示為數(shù)字,則會報錯。

            INCR?KEY_NAME?
          • DECR

            decr命令將 key 中儲存的數(shù)字值減一,和incr命令相似。

            DECR?KEY_NAME

          常用命令

          • STRLEN

            Strlen 命令將獲取指定 key 所儲存的字符串值的長度,如果key存儲的不是字符串類型或不存在時,返回錯誤。

            STRLEN?KEY_NAME
          • SETRANG

            Setrange命令是將從偏移量 offset 開始, 用 value 參數(shù)覆蓋鍵 key 儲存的字符串值。

            SETRANGE?key?offset?value

            不存在的鍵 key 當作空白字符串處理,如果鍵 key 原來儲存的字符串長度比偏移量小,那么原字符和偏移量之間的空白將用零字節(jié)("\x00" )進行填充。

          • GETRANG

            Getrange命令返回存儲在 key 中的字符串的子串,由 startend 偏移決定(都包括在內(nèi))。負數(shù)偏移提供相對字符串結(jié)尾的偏移。并且該命令會通過將結(jié)果范圍限制為字符串的實際長度來處理超出范圍的請求。

            ?GETRANGE?key?start?end

            當key不存在返回空字符串。

          • MSET

            命令設(shè)置多個 key 的值為各自對應(yīng)的 value。如果key存在,則會用新值替換舊值,如果key不存在,會重新創(chuàng)建,該命令總是返回“OK”,因為 MSET不會失敗。

            MSET?key?value?[key?value?...]
          • MGET

            命令返回所有(一個或多個)給定 key 的值,值的類型是字符串。如果給定的 key 里面有某個 key 不存在或者值不是字符串,那么這個 key 返回特殊值 nil 。

            ?MGET?key?[key?...]

          測試以上命令

          127.0.0.1:6379>?set?name?jiang?XX???#??XX表示只有鍵key存在的時候才會設(shè)置key的值
          (nil)
          127.0.0.1:6379>?set?name?jiang?NX???#??NX表示只有鍵key不存在的時候才會設(shè)置key的值
          OK
          127.0.0.1:6379> get name ??#??返回與鍵?`key`?相關(guān)聯(lián)的字符串值。
          "jiangyou"
          127.0.0.1:6379>?get?age????#??鍵key不存在的時候返回nil
          (nil)
          127.0.0.1:6379>?APPEND?name?????#??將value追加到key原值的末尾,返回值的總長度
          (integer)?14
          127.0.0.1:6379>?get?name?
          "jiangyou"
          127.0.0.1:6379>?set?age?24?EX?30???#??設(shè)置age?的值,并設(shè)置了過期時間??EX表示秒
          OK
          127.0.0.1:6379>?incr?age???????#??在age上進行增?1
          (integer)?25
          127.0.0.1:6379>?get?age
          "25"
          127.0.0.1:6379>?decr?age???????#??在age上進行減?1
          (integer)?24
          127.0.0.1:6379>?get?age
          "24"
          127.0.0.1:6379>?incr?name??????#??由于name值不能表示數(shù)字,無法增1
          (error)?ERR?value?is?not?an?integer?or?out?of?range
          127.0.0.1:6379>?STRLEN?name????#??name對應(yīng)的string的長度
          (integer)?8
          127.0.0.1:6379>?SETRANGE?name?10?hahaha?????#?從偏移量為10?的位置開始加入hahaha
          (integer)?16
          127.0.0.1:6379>?get?name??????????????#?不足的用\x00?補充
          "jiangyou\x00\x00hahaha"
          127.0.0.1:6379>?GETRANGE?name?0?-1????#?獲取name的值,改方式類似于python的數(shù)組查找
          "jiangyou\x00\x00hahaha"
          127.0.0.1:6379>?MSET?age?26?home?liaoning???#??為多個key賦值
          OK
          127.0.0.1:6379> MGET age home addr ???#???查找多個key對應(yīng)的值,不存在的key返回nil。
          1)?"26"
          2)?"liaoning"
          3)?(nil)

          4、列表—list命令:

          基本命令

          • LPUSH

            Lpush 將一個或多個值插入到列表key 的頭部。如果 key 不存在,那么在進行 push 操作前會創(chuàng)建一個空列表。如果 key 對應(yīng)的值不是 list 類型,那么會返回一個錯誤??梢允褂靡粋€命令把多個元素 push 進入列表。

            LPUSH?key?value?[value?...]
          • RPUSH

            Rpush 將向存儲在 key 中的列表的尾部插入所有指定的值。如果 key 不存在,那么會創(chuàng)建一個空的列表然后再進行 push 操作。當 key 保存的不是列表,那么會返回一個錯誤。

            RPUSH?key?value?[value?...]
          • LRANGE

            Lrange將返回列表中指定區(qū)間內(nèi)的元素(閉區(qū)間),區(qū)間以偏移量 START 和 END 指定。其中 0 表示列表的第一個元素, 1 表示列表的第二個元素,以此類推。你也可以使用負數(shù)下標,以 -1 表示列表的最后一個元素, -2 表示列表的倒數(shù)第二個元素,以此類推。如果start大于最大小標,那么叫返回空列表。

            LRANGE?key?start?stop
          • LINDEX

            Lindex 將返回列表 key 里索引 index 位置存儲的元素。index 下標是從 0 開始索引的,所以 0 是表示第一個元素, 1 表示第二個元素,并以此類推。負數(shù)索引用于指定從列表尾部開始索引的元素,在這種方法下,-1 表示最后一個元素,-2 表示倒數(shù)第二個元素,并以此往前推。當 key 值不是列表的時候,會返回錯誤。

            LINDEX?key?index
          • LLEN

            Llen 將用于返回存儲在 key 中的列表長度。如果 key 不存在,則 key 被解釋為一個空列表,返回 0 。如果 key 不是列表類型,返回一個錯誤。

            LLEN?key

          常用命令

          • LREM

            Lrem將用于從列表 key 中刪除前 count 個值等于 element 的元素。這個 count 參數(shù)通過下面幾種方式影響這個操作,如果count > 0, 從頭到尾刪除值為 value 的元素;如果count < 0,將從尾到頭刪除值為 value 的元素;如果 count = 0 將移除所有值為 value 的元素

            LREM?key?count?value
          • LSET

            Lset 將用于設(shè)置列表 key 中 index 位置的元素值為 element。

            LSET?key?index?value
          • LINSERT

            Linsert 將用于把 element 插入到列表 key 的前面或后面。當 key 不存在時,這個list會被看作是空list,什么都不執(zhí)行;當 key 存在,值不是列表類型時,返回錯誤。

            LINSERT?key?BEFORE|AFTER?pivot?value

          測試上面命令:

          127.0.0.1:6379>?RPUSH?myarrs?1?1?1?1?2?2???#??從list的右邊開始往myarrs里面添加值
          (integer)?6
          127.0.0.1:6379>?LRANGE?myarrs?0?-1???????#?返回myarrs的List中所有值
          1)?"1"
          2)?"1"
          3)?"1"
          4)?"1"
          5)?"2"
          6)?"2"
          127.0.0.1:6379>?LPUSH?myarrs?0?0?-1???#?從list的左邊開始往myarrs里面添加值
          (integer)?9
          127.0.0.1:6379>?LRANGE?myarrs?0?-1
          1)?"-1"
          2)?"0"
          3)?"0"
          4)?"1"
          5)?"1"
          6)?"1"
          7)?"1"
          8)?"2"
          9)?"2"
          127.0.0.1:6379>?LINDEX?myarrs?-2????#?根據(jù)索引返回List中的值
          "2"
          127.0.0.1:6379>?LLEN?myarrs?????????#?返回List中元素個數(shù)
          (integer)?9
          127.0.0.1:6379>?LREM?myarrs?2?1?????#?刪除myarrs中的1??count為2??所以從頭往尾刪除兩個1
          (integer)?2
          127.0.0.1:6379>?LRANGE?myarrs?0?-1
          1)?"-1"
          2)?"0"
          3)?"0"
          4)?"1"
          5)?"1"
          6)?"2"
          7)?"2"
          127.0.0.1:6379>?LREM?myarrs?-1?1????#?刪除myarrs中的1??count為-1??所以從尾往頭刪除1個1
          (integer)?1
          127.0.0.1:6379>?LRANGE?myarrs?0?-1??
          1)?"-1"
          2)?"0"
          3)?"0"
          4)?"1"
          5)?"2"
          6)?"2"
          127.0.0.1:6379>?LREM?myarrs?0?2???#?刪除myarrs中的2??count為0??刪除所有等于2的元素
          (integer)?2
          127.0.0.1:6379>?LRANGE?myarrs?0?-1
          1)?"-1"
          2)?"0"
          3)?"0"
          4)?"1"
          127.0.0.1:6379>?LSET?myarrs?2?5????#?根據(jù)索引設(shè)置myarrs的值,將索引為2?的位置賦值為5
          OK
          127.0.0.1:6379>?LRANGE?myarrs?0?-1??
          1)?"-1"
          2)?"0"
          3)?"5"
          4)?"1"
          127.0.0.1:6379>?LINSERT?myarrs?before?5?4??#?在第一個值為5的位置的前面插入一個4
          (integer)?5
          127.0.0.1:6379>?LRANGE?myarrs?0?-1
          1)?"-1"
          2)?"0"
          3)?"4"
          4)?"5"
          5)?"1"

          5、哈希類型—hash命令:

          hash類似于java中的HashMap,在Reids中做了更多的優(yōu)化。此外hash是一個sytring類型的field和value的映射表,特別適合用于存儲對象。例如我們可以借用hash數(shù)據(jù)結(jié)構(gòu)來存儲用戶信息,商品信息等。

          基本命令

          • HSET

            Hset 命令用于為存儲在 key 中的哈希表的 field 字段賦值 value 。如果哈希表不存在,一個新的哈希表被創(chuàng)建并進行 HSET 操作。如果字段(field)已經(jīng)存在于哈希表中,舊值將被覆蓋。

            HSET?key?field?value
          • HGET

            Hget 命令用于返回哈希表中指定字段 field 的值。如果給定的字段或 key 不存在時,返回 nil 。

            HGET?key?field
          • HMSET

            Hmset 命令用于同時將多個 field-value (字段-值)對設(shè)置到哈希表中。此命令會覆蓋哈希表中已存在的字段,如果哈希表不存在,會創(chuàng)建一個空哈希表,并執(zhí)行 HMSET 操作。

            HMSET?key?field?value?[field?value?...]
          • HGETALL

            Hgetall 命令用于返回存儲在 key 中的哈希表中所有的域和值。返回值以列表形式返回哈希表的字段及字段值,若 key 不存在,返回空列表。

            HGETALL?key
          • HDEL

            Hdel 命令用于刪除哈希表 key 中的一個或多個指定域,不存在的域?qū)⒈缓雎浴H绻?key 不存在,會被當作空哈希表處理并返回 0 。

            HDEL?key?field?[field?...]

          常用命令

          • HEXISTS

            Hexists 命令用于查看哈希表的指定字段field 是否存在。如果表含有給定字段field會返回1,否則返回0。

            HEXISTS?key?field
          • HKEYS

            Hkeys返回存儲在 key 中哈希表的所有域。當 key 不存在時,返回空表。

            HKEYS?key
          • HVALS

            Hvals 命令返回哈希表所有域(field)的值。當 key 不存在時,返回空表。

            HVALS?key

          測試以上命令

          127.0.0.1:6379>?HSET?userinfo?name?jiangyou?????#??創(chuàng)建新的hash表,并存入對象userinfo的name屬性
          (integer)?1?????????????????????????????????????#??返回賦值成功域的個數(shù)
          127.0.0.1:6379>?HSET?userinfo?age?26?home?liaoming?school?neu????#??設(shè)置userinfo對象的多個域的值
          (integer)?3?????????????????????????????????????#??返回賦值成功域的個數(shù)
          127.0.0.1:6379>?HKEYS?userinfo??????????????????#??查看userinfo的所有域的名
          1)?"name"
          2)?"age"
          3)?"home"
          4)?"school"
          127.0.0.1:6379>?HKEYS?users?????????????????????#??當key不存在時,返回空
          (empty?list?or?set)
          127.0.0.1:6379>?HVALS?userinfo??????????????????#??返回key值的所有域的值
          1)?"jiangyou"
          2)?"26"
          3)?"liaoming"
          4)?"neu"
          127.0.0.1:6379>?HEXISTS?userinfo?name???????????#??查看哈希表的指定字段`name`?該字段存在,返回1
          (integer)?1
          127.0.0.1:6379>?HEXISTS?userinfo?addr???????????#??查看哈希表的指定字段`addr`?該字段存在,返回0
          (integer)?0
          127.0.0.1:6379>?HGETALL?userinfo????????????????#??查看哈希表中存儲在?`key`?中的所有的域和值
          1)?"name"
          2)?"jiangyou"
          3)?"age"
          4)?"26"
          5)?"home"
          6)?"liaoming"
          7)?"school"
          8)?"neu"
          127.0.0.1:6379> HGETALL users ??????????????????#??`key`?不存在,會被當作空哈希表處理并返回。
          (empty?list?or?set)
          127.0.0.1:6379> HDEL userinfo school home ??????#???刪除哈希表 key 中的一個或多個指定域,返回的為成功刪除的域的個數(shù)。
          (integer)?2
          127.0.0.1:6379>?HGETALL?userinfo
          1)?"name"
          2)?"jiangyou"
          3)?"age"
          4)?"26"

          6、集合類型—set命令:

          基本命令

          • SADD

            Sadd 將命令將一個或多個成員元素加入到集合中,已經(jīng)存在于集合的成員元素將被忽略。假如集合 key 不存在,則創(chuàng)建一個只包含被添加的元素作為成員的集合。當集合 key 不是集合類型時,返回一個錯誤。

            ?SADD?key?member?[member?...]
          • SMEMBERS

            Smembers 將返回存儲在 key 中的集合的所有的成員。不存在的集合被視為空集合。

            ?SMEMBERS?key??
          • SISMEMBER

            Sismember 將用于判斷元素 member 是否集合 key 的成員。如果成員元素是集合的成員,返回 1 ;如果成員元素不是集合的成員,或 key 不存在,返回0。

            ?SISMEMBER?key?member
          • SCARD

            Scard 將返回集合中元素的數(shù)量。

            ?SCARD?key?
          • SREM

            Srem將在集合中刪除指定的元素。如果指定的元素不是集合成員則被忽略。如果集合 key 不存在則被視為一個空的集合,該命令返回0。如果key的類型不是一個集合,則返回錯誤。

            ?SCARD?key?member?[member?...]

          常用命令

          • SRANDMEMBER

            Srandmember 將僅使用key 參數(shù),那么隨機返回集合key 中的一個隨機元素。如果count是整數(shù)且小于元素的個數(shù),返回含有 count 個不同的元素的數(shù)組,如果count是個整數(shù)且大于集合中元素的個數(shù)時,返回整個集合的所有元素,當count是負數(shù),則會返回一個包含count的絕對值的個數(shù)元素的數(shù)組,如果count的絕對值大于元素的個數(shù),則返回的結(jié)果集里會出現(xiàn)一個元素出現(xiàn)多次的情況。

            ?SRANDMEMBER?key?[count]
          • SPOP

            Spop 將從集合 key中刪除并返回一個或多個隨機元素。這個命令和 SRANDMEMBER相似, SRANDMEMBER 只返回隨機成員但是不刪除這些返回的成員。

            ?SRANDMEMBER?key?[count]

          測試以上命令

          127.0.0.1:6379>?SADD?name?zhangsan?lisi?wangwu???#??賦值key為name的set集合,返回賦值成功的個數(shù)
          (integer)?3
          127.0.0.1:6379> SMEMBERS name ???????????????????#??查看存儲在name中的集合的所有的成員。
          1)?"zhangsan"
          2)?"lisi"
          3)?"wangwu"
          127.0.0.1:6379>?SISMEMBER?name?zhangsan??????????#??判斷元素?zhangsan?是否集合?name?的成員,如果是??返回1
          (integer)?1
          127.0.0.1:6379>?SISMEMBER?name?xuliu?????????????#??判斷元素?xuliu?是否集合?name?的成員,如果不是??返回0
          (integer)?0
          127.0.0.1:6379>?SCARD?name
          (integer)?3
          127.0.0.1:6379> SREM name zhangsan xuliu ??????#??刪除 name 的成員,如果存在直接刪除,否則忽略。返回刪除成功的元素個數(shù)
          (integer)?1
          127.0.0.1:6379>?SMEMBERS?name
          1)?"lisi"
          2)?"wangwu"
          127.0.0.1:6379>?SRANDMEMBER?name?5??#?隨機返回集合name中的一個隨機元素,count為5?大于集合個數(shù),返回整個集合元素?
          1)?"lisi"
          2)?"wangwu"
          127.0.0.1:6379>?SRANDMEMBER?name?1??#?隨機返回集合name中的一個隨機元素,count為1?隨機返回集合中任意一個元素
          1)?"wangwu"
          127.0.0.1:6379>?SRANDMEMBER?name?-5??#?隨機返回集合name中的一個隨機元素,count為-5?返回的結(jié)果集里會出現(xiàn)一個元素出現(xiàn)多次
          1)?"wangwu"
          2)?"lisi"
          3)?"lisi"
          4)?"lisi"
          5)?"wangwu"
          127.0.0.1:6379>?SPOP?name?0??#?隨機刪除并返回集合name中的一個或多個隨機元素,count為0?返回的結(jié)果集里不會出現(xiàn)任何元素
          (empty?array)
          127.0.0.1:6379>?SPOP?name?1??#?隨機刪除并返回集合name中的一個或多個隨機元素,count為1?返回的結(jié)果集里會出現(xiàn)一個元素出現(xiàn)多次
          1)?"lisi"
          127.0.0.1:6379> SPOP name -5 #?隨機刪除并返回集合name中的一個或多個隨機元素,count 不能為負數(shù)。
          (error)?ERR?value?is?out?of?range,?must?be?positive

          7、有序集合類型—sortedset命令:

          基本命令

          • ZADD

            Zadd 將一個或多個 member 元素及其 score 值加入到有序集 key 當中。如果某個 member 已經(jīng)是有序集的成員,那么更新這個 memberscore 值,并通過重新插入這個 member 元素,來保證該 member 在正確的位置上。如果有序集合 key 不存在,則創(chuàng)建一個空的有序集并執(zhí)行 ZADD操作。當 key 存在但不是有序集類型時,返回一個錯誤。score 值可以是整數(shù)值或雙精度浮點數(shù),score 可為正也可以為負。

            ZADD?key?[NX|XX]?[CH]?[INCR]?score?member?[score?member?...]

            舉例子:

            • XX: 僅更新存在的成員,不添加新成員。
            • NX: 不更新存在的成員。只添加新成員。
            • LT: 更新新的分值比當前分值小的成員,不存在則新增。
            • GT: 更新新的分值比當前分值大的成員,不存在則新增。
            • CH: 返回變更成員的數(shù)量。變更的成員是指 新增成員score值更新的成員,命令指明的和之前score值相同的成員不計在內(nèi)。注意: 在通常情況下,ZADD返回值只計算新添加成員的數(shù)量。
            • INCR: ZADD 使用該參數(shù)與 ZINCRBY 功能一樣。一次只能操作一個score-element對。
          • ZRANG

            Zrange將返回有序集中,指定區(qū)間內(nèi)(閉區(qū)間)的成員,其中成員的按分數(shù)值遞增(從小到大)來排序,具有相同分數(shù)值的成員按字典序(lexicographical order )來排列。如果你需要成員按值遞減(從大到小)來排列,可以使用 ZREVRANGE命令。下標參數(shù) startstop 都以 0 為底,也就是說,以 0 表示有序集第一個成員,以 1 表示有序集第二個成員,以此類推。其中 start和stop參數(shù)的細節(jié)同 ZRANG命令。

            ZRANGE?key?start?stop?[WITHSCORES]
          • ZREVRANGE

            Zervrange 將返回有序集key中,指定區(qū)間內(nèi)的成員。其中成員的位置按score值遞減(從高到低)來排列。具有相同score值的成員按字典序的反序排列。除了成員排序相反外,ZREVRANGE命令的其他方面和ZRANGE命令一樣。

            ZREVRANGE?key?start?stop?[WITHSCORES]
          • ZREM

            Zrem 將從有序集合key中刪除指定的成員member。如果member不存在則被忽略。當key存在,但是不是有序集合類型時,返回類型錯誤。返回的是從有序集合中刪除的成員個數(shù),不包括不存在的成員。

            ZREM?key?member?[member?...]
          • ZCARD

            Zcard 將返回有序集的成員個數(shù)。當 key 不存在時,返回 0

            ZCARD?key

          常用命令

          • ZRANGEBYSCORE

            該指令將返回有序集 key 中,所有 score 值介于 minmax 之間(包括等于 minmax )的成員。有序集成員按 score 值遞增(從小到大)次序排列。具有相同 score 值的成員按字典序來排列(該屬性是有序集提供的,不需要額外的計算)??蛇x的 LIMIT 參數(shù)指定返回結(jié)果的數(shù)量及區(qū)間(就像SQL中的 SELECT LIMIT offset, count ),注意當 offset 很大時,定位 offset 的操作可能需要遍歷整個有序集,此過程最壞復(fù)雜度為 O(N) 時間。可選的 WITHSCORES 參數(shù)決定結(jié)果集是單單返回有序集的成員,還是將有序集成員及其 score 值一起返回。

            ZRANGEBYSCORE?key?min?max?[WITHSCORES]?[LIMIT?offset?count]
          • ZREVRANGEBYSCORE

            該指令將返回有序集合中指定分數(shù)區(qū)間的成員列表。有序集成員按分數(shù)值遞增(從小到大)次序排列。具有相同分數(shù)值的成員按字典序來排列(該屬性是有序集提供的,不需要額外的計算)。默認情況下,區(qū)間的取值使用閉區(qū)間 (小于等于或大于等于),你也可以通過給參數(shù)前增加 ( 符號來使用可選的開區(qū)間 (小于或大于)。可選的LIMIT參數(shù)指定返回結(jié)果的數(shù)量及區(qū)間(類似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍歷整個有序集合,這會增加O(N)的復(fù)雜度??蛇x參數(shù)WITHSCORES會返回元素和其分數(shù),而不只是元素。

            ZREVRANGEBYSCORE??key?min?max?[WITHSCORES]?[LIMIT?offset?count]
          • ZCOUNT

            Zcount 將返回有序集 key 中, score 值在 minmax 之間(默認包括 score 值等于 minmax )的成員的數(shù)量。

            ZCOUNT?key?min?max

          Python調(diào)用Redis

          在Python中,目前可以通過一個redis模塊來實現(xiàn)操控Redis,下面我們簡單的介紹一下關(guān)于使用redis模塊。

          安裝Redis模塊

          如果是在Windows 系統(tǒng),安裝 redis 模塊可以使用以下命令:

          python?-m?pip?install?redis

          如果是 Linux 系統(tǒng),需要執(zhí)行以下命令來安裝:

          sudo?pip3?install?redis

          如果是使用Anaconda管理環(huán)境,也可以使用以下命令安裝:

          conda?install?redis

          Python連接Redis

          Redis模塊提供了兩種連接的模式:直連模式和連接詞模式。

          直連模式

          直連模式的方式簡單方便,適合少量長期連接的場景。其中host參數(shù)是ip地址,如果Redis服務(wù)存在于本地,可以使用127.0.0.1,或者換成Redis服務(wù)所在的ip地址。db表示當前選擇的庫,其參數(shù)值可以是 0-15;如果設(shè)置連接數(shù)據(jù)庫的密碼,那么就需要使用password進行驗證。

          import?redis

          r?=?redis.Redis(host='127.0.0.1',port=6379,db=0,password='')
          r.set('name':'jiangyou')
          print(r.get('name'))

          連接池模式

          連接池模式是使用 connection pool(連接池)來管理 redis server 的所有連接,每個Redis實例會維護自己的連接池來管理管理對一個 redis server 所有的連接,避免每次建立,釋放連接的開銷。

          import?redis

          pool?=?redis.ConnectionPool(host="127.0.0.1",port=6379,db=0,password="",decode_responses=True,?max_connections=10)
          r1?=?redis.Redis(connection_pool=pool)???#??第一個客戶端訪問
          r2?=?redis.Redis(connection_pool=pool)???#??第二個客戶端訪問

          上面的參數(shù),decode_responses=True 可以使得redis取出的結(jié)果改成字符串,其默認的是字節(jié), max_connections參數(shù)可以設(shè)置最大連接數(shù)量,這樣當有新的客戶端請求連接時,只需要去連接池獲取即可,這樣就可以把一個連接共享給多個客服端,減少每次連接所消耗的時間以及資源。

          基本操作

          在Redis模塊中,提供了RedisStrictRedis來支持Redis訪問和操作。其中 StrictRedis 使用python基于Redis協(xié)議實現(xiàn)了所有官方的Redis操作命令,也就是說其實對于python操作redis的API接口和上面提到的Redis官方接口一樣。因此下面我們就簡單介紹一些常用的方法。

          1. String操作

            import?redis

            pool?=?redis.ConnectionPool(host="127.0.0.1",port=6379,db=0,password="",decode_responses=True,max_connections=10)
            r?=?redis.StrictRedis(connection_pool=pool)

            r.set('name','jiang')
            r.append("name","you")?#?在redis?name對應(yīng)的值后面追加內(nèi)容

            r.mset({'age':'26','home':'liaoning'})
            print(r.mget('name','age','home'))
            print("name 長度:%d"%r.strlen('name'))???#查看ame對應(yīng)值的長度

            r.incrby('age',5)???#數(shù)值操作??將age對應(yīng)的值?加5
            print(r.get('age'))
            r.decrby('age',5)???#數(shù)值操作??將age對應(yīng)的值?減5
            print(r.get('age'))
            r.incrbyfloat('age',5.2)??#將age對應(yīng)的值?加5.2
            print(r.get('age'))
            r.incrbyfloat('age',-10.5)??#將age對應(yīng)的值?減10.5
            print(r.get('age'))

            r.setrange('name',5,'hahaha')??#?修改字符串內(nèi)容,從指定字符串索引開始向后替換。
            print(r.getrange('name',0,6))???#??獲取子序列(根據(jù)字節(jié)獲取,非字符),閉區(qū)間

            r.delete('name')??#刪除key

            運行結(jié)果

            ['jiangyou',?'26',?'liaoning']
            name 長度:8
            31
            26
            31.2
            20.7
            jiangha
          2. Hash操作

            import?redis

            pool?=?redis.ConnectionPool(host="127.0.0.1",port=6379,db=0,password="",decode_responses=True,max_connections=10)
            r?=?redis.StrictRedis(connection_pool=pool)

            r.hset('user1','name','zhangsan')???# user1對應(yīng)的hash中設(shè)置一個鍵值對(不存在,則創(chuàng)建;否則,修改)
            r.hset('user1','age','22')??????????# user1對應(yīng)的hash中設(shè)置一個鍵值對(不存在,則創(chuàng)建;否則,修改)
            r.hincrbyfloat('user1','age',0.5)???#?自增user1對應(yīng)的hash中的指定key的值,不存在則創(chuàng)建key=amount
            print(r.hmget('user1','name','age'))??#?在user1對應(yīng)的hash中獲取多個key的值

            #?一次性設(shè)置多個field和value
            user_dict?=?{
            ??'password':'123',
            ??'gender':'M',
            ??'home':'遼寧'
            }
            r.hmset('user1',user_dict)????????#??在user1對應(yīng)的hash中批量設(shè)置鍵值對?

            print("user1中存在鍵值對的個數(shù):%d "%r.hlen('user1'))?#??獲取所有數(shù)據(jù),字典類型
            print("user1中存在鍵值對的具體信息:%s"%r.hgetall('user1'))?#??獲取所有數(shù)據(jù),字典類型
            print(r.hkeys("user1"))??#?獲取所有fields字段
            print(r.hvals("user1"))??#?獲取所有fields字段的values值

            if?r.hexists("user1","home"):????????????#??檢查user1對應(yīng)的hash是否存在當前傳入的home
            ????r.hdel("user1",'home')???????????????#??將user1對應(yīng)的hash中指定key的鍵值對刪除
            ????print("已刪除該鍵!??!")
            else:
            ????print("不存在該鍵?。?!")

            運行結(jié)果

            ['zhangsan',?'22.5']
            user1中存在鍵值對的個數(shù):5?
            user1中存在鍵值對的具體信息:{'name':?'zhangsan',?'age':?'22.5',?'password':?'123',?'gender':?'M',?'home':?'遼寧'}
            ['name',?'age',?'password',?'gender',?'home']
            ['zhangsan',?'22.5',?'123',?'M',?'遼寧']
            已刪除該鍵!!
          3. List操作

            import?redis

            pool?=?redis.ConnectionPool(host="127.0.0.1",port=6379,db=0,password="",decode_responses=True,max_connections=10)
            r?=?redis.StrictRedis(connection_pool=pool)

            r.lpush('database','sql','mysql','redis')?????#???在database對應(yīng)的list中添加元素,每個新的元素都添加到列表的最左邊
            print(r.lrange('database',0,-1))?

            r.linsert('database','before','mysql','mongodb')???#???在database對應(yīng)的列表的某一個值前或后插入一個新值,其含義為在第三個參數(shù)的前(before)或后(after)?插入?yún)?shù)四

            print(r.lrange('database',0,-1))????????#??在database對應(yīng)的列表分片獲取數(shù)據(jù)

            print("database中元素個數(shù):%d"%r.llen('database'))??#??database對應(yīng)的list元素的個數(shù)

            print("database中第2個元素:%s"%r.lindex('database',2))??#在database對應(yīng)的列表中根據(jù)索引獲取列表元素

            r.lset('database',?0,?'redisdb')???#??對database對應(yīng)的list中的某一個索引位置重新賦值?????
            print(r.lrange('database',0,-1))???

            print(r.rpop('database'))?????#??在database對應(yīng)的列表的右側(cè)獲取第一個元素并在列表中移除,返回值則是第一個元素

            print(r.ltrim('database',0,1))???#?在database對應(yīng)的列表中移除沒有在start-end索引之間的值

            while?True:
            ??result?=?r.brpop('database',1)?????#?從一個列表的右側(cè)移除一個元素并將其添加到另一個列表的左側(cè)??[如果列表中為空時,則返回None]
            ??if?result:
            ??????print(result)
            ??else:
            ??????break
            r.delete('database')

            運行結(jié)果

            ['redis',?'mysql',?'sql']
            ['redis',?'mongodb',?'mysql',?'sql']
            database中元素個數(shù):4
            database中第2個元素:mysql
            ['redisdb',?'mongodb',?'mysql',?'sql']
            sql
            True
            ('database',?'mongodb')
            ('database',?'redisdb')
          4. Set操作

            import?redis

            pool?=?redis.ConnectionPool(host="127.0.0.1",port=6379,db=0,password="",decode_responses=True,max_connections=10)
            r?=?redis.StrictRedis(connection_pool=pool)


            r.sadd("name","zhangsan")????????#??給name對應(yīng)的集合中添加元素
            r.sadd("name","zhangsan","lisi","wangwu")


            print(r.smembers('name'))?????????#??獲取name對應(yīng)的集合的所有成員

            print(r.scard("name")?)???????????????#??獲取name對應(yīng)的集合中的元素個數(shù)

            print(r.sismember('name','zhangsan'))???#??檢查value是否是name對應(yīng)的集合內(nèi)的元素,返回值為True或False

            print(r.spop('name'))?????#??隨機刪除并返回指定集合的一個元素
            print(r.smembers('name'))?

            #?srem(name,?value)
            print(r.srem("name",?"zhangsan"))??????????#??刪除集合中的某個元素
            print(r.smembers('name'))?
            ????????????
            r.sadd("name","a","b")
            r.sadd("name1","b","c")
            r.sadd("name2","b","c","d")

            print(r.sinter("name","name1","name2"))??#??獲取多個name對應(yīng)集合的交集

            print(r.sunion("name","name1","name2"))???#??獲取多個name對應(yīng)的集合的并集

            print(r.sdiff("name","name1","name2"))???#??在第一個name對應(yīng)的集合中且不在其他name對應(yīng)的集合的元素集合

            r.flushall()

            運行結(jié)果

            {'zhangsan',?'lisi',?'wangwu'}
            3
            True
            lisi
            {'zhangsan',?'wangwu'}
            1
            {'wangwu'}
            {'b'}
            {'d',?'c',?'b',?'wangwu',?'a'}
            {'wangwu',?'a'}
          5. SortedSet操作

            import?redis

            pool?=?redis.ConnectionPool(host="127.0.0.1",port=6379,db=0,decode_responses=True,max_connections=10)
            r?=?redis.StrictRedis(connection_pool=pool)

            mapping?=?{
            ????'zhangsan':85,
            ????'lisi':92,?
            ????'wangwu':76
            }
            r.zadd('C++',mapping,nx=True)???????#??在C++對應(yīng)的有序集合中添加元素
            print(r.zrange('C++',0,-1,withscores=True))???#??獲取C++對應(yīng)的有序集合的所有元素

            print(r.zcard("C++"))???????????????#?獲取C++對應(yīng)的有序集合元素的數(shù)量
            print(r.zcount('C++',min=0,max=90))?#?獲取C++對應(yīng)的有序集合中分數(shù)?在?[min,max]?之間的個數(shù)

            r.zincrby(name='C++',value='lisi',amount=3)???#?增加C++對應(yīng)的有序集合的lisi對應(yīng)的分數(shù)
            print(r.zrange('C++',0,-1,desc=False,withscores=True))??#?按照索引范圍獲取C++對應(yīng)的有序集合的元素,排序規(guī)則,默認按照分數(shù)從小到大排序
            print(r.zrevrange('C++',0,-1,withscores=True))??#?按照索引范圍獲取C++對應(yīng)的有序集合的元素,排序規(guī)則,默認按照分數(shù)從大到小排序

            print(r.zrangebyscore('C++',70,90))??#?按照分數(shù)范圍獲取C++對應(yīng)的有序集合的元素,排序規(guī)則,默認按照分數(shù)從小到大排序
            print(r.zrevrangebyscore('C++',90,70))??#?按照分數(shù)范圍獲取C++對應(yīng)的有序集合的元素,排序規(guī)則,默認按照分數(shù)從大到小排序

            print(r.zrank('C++','lisi'))???#? Zrank 返回有序集中指定成員的排名,有序集成員按分數(shù)值遞增(從小到大)順序排列。
            print(r.zrevrank('C++','lisi'))???#? Zrevrank 返回有序集中指定成員的排名,有序集成員按分數(shù)值遞增(從大到小)順序排列。

            mapping?=?{
            ????'xuliu':74,
            ????'lisi':82,?
            ????'wangwu':87
            }
            r.zadd('python',mapping,nx=True)
            r.zinterstore('sum_score_i',['C++','python'],aggregate='sum')???#?獲取兩個有序集合的交集,如果遇到相同值不同分數(shù),則按照aggregate進行操作
            print(r.zrange('sum_score_i',0,-1,withscores=True))
            print(r.zunionstore('sum_score_u',['C++','python'],'min'))??#?獲取兩個有序集合的并集,如果遇到相同值不同分數(shù),則按照aggregate進行操作
            print(r.zrange('sum_score_u',0,-1,withscores=True))

            r.zrem('C++',?'zhangsan')?????????????????#??刪除C++對應(yīng)的有序集合中值是zhangsan的成員
            print(r.zrange('C++',0,-1,withscores=True))

            r.zremrangebyscore('C++',?min=80,?max=100)??????#?刪除C++對應(yīng)的有序集合中值是zhangsan的成員
            print(r.zrange('C++',0,-1,withscores=True))

            r.zremrangebyrank('python',?min=1,?max=3)???????#?根據(jù)排行范圍刪除
            print(r.zrange('python',0,-1,withscores=True))

            運行結(jié)果

            [('wangwu',?76.0),?('zhangsan',?85.0),?('lisi',?92.0)]
            3
            2
            [('wangwu',?76.0),?('zhangsan',?85.0),?('lisi',?95.0)]
            [('lisi',?95.0),?('zhangsan',?85.0),?('wangwu',?76.0)]
            ['wangwu',?'zhangsan']
            ['zhangsan',?'wangwu']
            2
            0
            [('wangwu',?163.0),?('lisi',?177.0)]
            4
            [('xuliu',?74.0),?('wangwu',?76.0),?('lisi',?82.0),?('zhangsan',?85.0)]
            [('wangwu',?76.0),?('lisi',?95.0)]
            [('wangwu',?76.0)]
            [('xuliu',?74.0)]
          6. 管道操作

            Redis 模塊默認在執(zhí)行每次請求都會向連接池請求創(chuàng)建連接和斷開申請操作,如果想要在一次請求中指定多個命令,則可以使用pipline實現(xiàn)一次請求指定多個命令,并且默認情況下一次pipline 是原子性操作(即為一次操作)。

            ?import?redis

            pool?=?redis.ConnectionPool(host="127.0.0.1",port=6379,db=0,decode_responses=True,max_connections=10)
            r?=?redis.StrictRedis(connection_pool=pool)

            pipe?=?r.pipeline(transaction=True)

            pipe.set('name',?'jiangyou')
            pipe.set('age',?'age')
            pipe.execute()

            print(r.mget("name","age"))

            運行結(jié)果

            ['jiangyou',?'age']
          --end--


          掃碼即可加我微信

          學習交流

          老表朋友圈經(jīng)常有贈書/紅包福利活動

          瀏覽 75
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  激情偷乱人成视频在线观看 | 精品无码一区二区三区免费 | 久久7777 | 亚洲一级视频在线 | 久久色视频在线观看 |