程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python操作Redis從入門到精通附代碼(全)

編輯:Python

目錄

  • 前言
  • 1. 連接Redis
  • 2. 基本類型
    • 2.1 String
    • 2.2 List
    • 2.3 Hash
    • 2.4 Set
    • 2.5 Zset
  • 3. 實戰
    • 3.1 普通連接
    • 3.2 連接池連接

前言

對於Redis的相應原理以及知識點對應的java版本,可看我之前的文章:(其知識點都是互通的)
Redis框架從入門到學精(全)

對於以上的前置知識如果了解了更好,如果不了解,就當是一種數據庫,上手也很快。
本身Redis就是一種可持久的Key-Value的數據庫,有豐富的數據結構等

通過pip install redis進行安裝導入redis的模塊包即可
如果在安裝以及使用的過程中遇到這些bug
可看我之前的文章:

  1. Redis (error) NOAUTH Authentication required.解決方法
  2. Redis Could not connect to Redis at 127.0.0.1:6379: Connection refused解決方法
  3. linux中設置redis的密碼
  4. Redis出現 Creating Server TCP listening socket *:6379: bind: No error 的解決方法(全)

1. 連接Redis

本身就是一種數據庫,操作數據庫第一就是連接Redis,本身有兩個類可以連接,官方提供了Redis(StrictRedis的子類)以及StrictRedis。

連接也有兩種方式:

第一種方式是正常連接:

# 導入redis的包
import redis
# 通過redis連接用戶名、端口、密碼以及db數據庫
redis_conn = redis.Redis(host='127.0.0.1', port= 6379, password= '?', db= 0,decode_responses=True)
redis_conn = redis.StrictRedis(host='127.0.0.1', port= 6379, password= '?', db= 0,decode_responses=True)

關於以上的連接參數中:
decode_responses=True輸出的時候變為字符串,默認輸出是字節(decode_responses可不用)

連接方式的第二種是:(使用連接池)
連接池的好處是通過連接池來管理其所有的連接,避免對建立釋放連接等開銷

import redis
redis_pool = redis.ConnectionPool(host='127.0.0.1', port= 6379, password= '?', db= 0)
# 通過調用連接池
redis_conn = redis.Redis(connection_pool= redis_pool)

2. 基本類型

在基本類型中介紹其方法的使用
正常連接之後 大部分都可通過如下查看其共性的東西:
通過set設置鍵值對:redis.set('manong',18)
獲取鍵值:redis.get('manong')
判斷鍵值是否存在:redis.exists('manong')
查看鍵值的類型:redis.type('manong')
獲取當前數據庫中鍵值對數目:redis.dbsize()
以及其他的函數,可參照官網進行學習

基本的使用類型以及方法會用即可

2.1 String

其實Sting類在上面的展示中已經有使用到

函數:

描述函數用法設置單個鍵值對set(name, value, ex=None, px=None, nx=False, xx=False, keepttl=False, get=False, exat=None, pxat=None)如果key不存在就添加成功setnx(name, value)設置key的過期時間setex(name, time, value)以秒為單位,psetex(name, time_ms, value)以毫秒為單位獲取單個鍵值對get(name)設置多個鍵值對mset(*args, **kwargs)獲取多個鍵值對mget(keys, *args)值不存在設新鍵值對getset(name, value)根據索引修改值setrange(name, offset, value)根據索引獲取值getrange(key, start, end)根據建值追加值append(key, value)獲取值長度strlen(name)

String還有一個特點是:可以設置自增類型(不同類型設置不同類型的自增,注意區分)

  • incr(name, amount=1)
  • incrbyfloat(name, amount=1.0)

對於上面各個函數的用法如下:
單個鍵值對的用法

r.set("name", "碼農研究僧")
r.get("name")
r.append("name", "大帥哥") # key後追加,不存在則不成功
""" 對於set的參數比較多,不同參數不同的延遲 """
r.setex("name", 10086, "碼農研究僧") # 10086秒後過期 
# 類似
r.set("name", "碼農研究僧", ex = 10086)
r.psetex("name", 10086, "碼農研究僧") # 10086毫秒後過期
# 類似
r.set("name","碼農研究僧",px = 10086)
r.setnx("name", "碼農研究僧") # key不存在設置成功,也就是 新建 鍵值
# 類似
r.set("name", "碼農研究僧",nx=True)
r.setxx("name", "碼農研究僧") # key存在設置成功,也就是 修改 鍵值
# 類似
r.set("name", "碼農研究僧",xx=True)

多個鍵值對的用法:

r.mset({
'k1': 'v1', 'k2': 'v2'}) # 設置多個值,傳入字典
r.mget("k1", "k2") # 返回一個列表,一次取出多個值
r.getset("name", "關注我") # 設置新值,並返回之前的值
# 類似
dict = {

'k1' : 'v1',
'k2' : 'v2'
}
r.mset(dict)

范圍以及自增的用法:

r.setrange("name", 2, "開發") # 從第2個位置開始替換(0開始數),原來是碼農研究僧,替換後是碼農開發
r.getrange("name", 2, 3) # 取中間子串,為開發
r.strlen("name") # 長度,不存在為0
r.incr("name", amount=3) # 以3為自增,不存在則以3為初值,不指定amount則默認為1
r.incrbyfloat("name", amount=0.3) # 以0.3自增, 同理
r.decr("name", amount=3) # 遞減同理
r.delete("name1") # 刪除

2.2 List

描述函數用法lpush(name,values)對應的name中往左添加list元素rpush(name,values)對應的name中往右添加list元素lpushx(name, value)往已有name的列表添加左元素,沒有無法創建rpushx(name, value)往已有name的列表添加左元素,沒有無法創建linsert(name, where, refvalue, value))通過refvalue的where(可以before或者after)插入valuer.lset(name, index, value)修改對應list列表中的某個索引值r.lrem(name, num, value)刪除list列表指定值lpop(name)刪除列表左邊的第一個元素,返回刪除的元素rpop(name)刪除列表右邊的第一個元素,返回刪除的元素ltrim(name, start, end)刪除索引之外的值lindex(name, index)根據索引獲取列表值rpoplpush(list1,anotherlist1)list1的列表中最右邊的值插入anotherlist1列表的最左邊brpoplpush(list1,anotherlist1, timeout=0)list1的列表中最左邊的值插入anotherlist1列表的最右邊blpop(keys, timeout)一次移除多個列表

插入元素具體的使用用法:

r.lpush("list1", 1,2,3) # 從左插入,通過r.lrange('list1',0,2)得到321。list1不存在會創建
r.rpush("list2", 1,2,3) # 從右插入,通過r.lrange('list2',0,2)得到123
r.lpushx("list1", 4,5) # 從左插入,通過r.lrange('list1',0,5)得到45321
r.rpushx("list1", 4,5) # 從右插入,通過r.lrange('list1',0,6)得到453216

其他的增刪改查的一些指標:(查看最後的值,通過r.lrange('list4',0,-1) ).
python的輸出格式有多種:可通過如下format格式print("list4:{}".format(r.lrange('list4',0,-1)))

r.lrange("list1",0,-1) # 默認是輸出全部值,返回所有列表
r.llen("list1") # 返回元素個數
r.lindex("list1", 1) # 通過下標1的取值
r.linsert("list1", "before", 5,3) # 5之前插入3,本身值為453216,最後為4353216
r.lset("list1", 2, 6) # 修改第2個元素為6,最後值為456216
r.rpush("list4", 2,2,1,2,3,4,5,6,1,1) # 從右插入,通過r.lrange('list4',0,-1)得到1212345611
r.lrem("list4", 1, 2) # 刪除左邊的第一個2
r.lrem("list4", -1, 1) # 刪除右邊的第一個1,負數為從後往前
r.lrem("list4", 0, 1) # 刪除所有的1
r.lpop("list4") # 刪除左邊第一個值並返回刪除值
r.rpop("list4") # 刪除右邊第一個值並返回刪除值
r.ltrim("list4", 2, 3) # 除了下標2到3的元素,其他都被刪除

2.3 Hash

描述函數用法hset(name, key, value)設置鍵值對。有即修改無即創建hget(name, key)取出單個key的值hmget(name, key,…)取出多個key的值hgetall(name)取出對應的所有鍵值對hkeys(name)取出所有的keyhvals(name)取出所有的valuehlen(name)取出鍵值對個數hexists(name, key)查看是否存在這個key

自增以及分片的函數
主要為了防止多次取值,撐爆內存
具體的思想通過

  1. 通過cursor的標志位置獲取數據
  2. match參數過濾,如果指定None則為所有key,如果指定key則過濾key出來
  3. count每次最少取key的個數,為None則為默認分片的個數

在應用場景中比較常用,所以單獨放在一個表格中:

描述函數用法hincrby(name, key, amount=?)對key自增正或者負hincrbyfloat(name, key, amount=?.0)對key自增正浮點數或者負浮點數hscan(name, cursor=0, match=None, count=None)指定游標獲取數據hscan_iter(name, match=None, count=None)同上,只不過將其封裝在迭代器

具體操作如下:

r.hset("names", "manong", "yanjiuseng") # 設置鍵值對
r.hmset("names", {
"manong": "yanjiuseng", ....}) # 設置多個鍵值對,redis4.0版本前
r.hset("names", mapping={
"manong": "yanjiuseng", ...}) # 設置多個鍵值對,redis4.0版本後
r.hget("names", "manong") # 取出key中對應的value值,返回其value值
r.hmget("names", ["manong", "age"]) # 取出多個key中對應的value值,返回其value值
r.hgetall("names") # 取出多有的鍵值對(字典)
r.hkeys("names") # 取出所有key(列表)
r.hvals("names") # 取出所有value(列表)
hlen("names") # 獲取鍵值對個數
r.hexists("names", "ma") # 查看是否存在這個key
r.hincrby("names", "age", amount=1)
# 自增1,age本身這個就沒設置,則以amount為初始,也可為負數

分片讀取的具體操作:

cursor1, data1 = r.hscan('names', cursor=0, match=None, count=None)
cursor2, data2 = r.hscan('names', cursor=cursor1, match=None, count=None)
r.hscan_iter("names", match=None, count=None) # 取出所有key,注意這裡要用遍歷,將其值進行遍歷出來
# 具體如下
for item in r.hscan_iter('xx'):
print item

2.4 Set

set元素本身是無序不可重復

描述函數用法sadd(name,values)集合中添加一個或多個元素sismember(name, value)判斷集合name中是否有對應value元素,返回false或者truesmove(src, dst, value)將src集合中的value元素移動到dst集合中sdiff(keys, *args)返回只存在第一個集合names中,之後的names集合都排除掉(差集)sdiffstore(dest, keys, *args)只存在第二個集合的names,之後的names集合都排除掉,放在第一個dest集合中sinter(keys, *args)多個集合names取交集sinterstore(dest, keys, *args)多個names取交集,存放在第一個dest集合中sunion(keys, *args)多個集合names取並集sunionstore(dest,keys, *args)多個集合names取並集,存放在第一個dest集合中spop(name)隨機刪除元素,並且返回輸出該元素srem(name, values)刪除集合中指定的value值,並返回已經刪除的元素個數

新增元素以及查詢等操作:

r.sadd("names", "ma", "nong", "yan", "jiu", "seng") # 返回集合長度個數5
r.sismember("names", "ma") # 查詢 ma 元素是否存在,返回false或者true操作
r.scard("names") # 獲取集合元素個數
# 補充測試輸出的時候,可以通過如下:
print('集合元素個數:{}'.format(r.scard("names")))
r.smembers("names") # 返回所有集合元素
r.sscan('names') #返回集合的所有元素(以元祖形式展示)
r.scan_iter("names") # 返回集合所有元素(需要通過遍歷的形式輸出)
# 例如
for i in r.sscan_iter("names"):
print(i)

差集的操作:

r.sdiff("names1", "names2") # 返回存在names1不存在names2的集合元素
r.sdiffstore("names3", "names1", "names2") # 存在names1不存在names2的集合元素,存放在names3中,並且輸出這個集合

交集的操作:

r.sinter("names1", "names2") # 返回names1和names2的交集元素
r.sinterstore("names3", "names", "names2") # 把names和names2的交集存到names3,返回names3的元素

並集的操作:

r.sunion("names1", "names2") # 返回names1和names2的並集元素
r.sunionstore("names3", "names1", "names2") # 把names和names2的並集存到names3,返回names3的元素

差集的操作:

r.spop("names") # 隨機刪除一個元素,並且將這個元素返回輸出
r.srem("names", "ma") # 刪除指定元素ma,返回已經刪除的個數

2.5 Zset

這個zset與set的區別在於
zset為有序集合,會為元素進行排序

描述函數用法zadd(name, {‘k1’:v1,‘k2’:v2})有序集合中添加元素zcard(name)獲取有序集合元素個數r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)獲取有序集合的元素。desc 為排序規則, 默認是value從小到大排序。withscores是否獲取value,默認不獲取value只有key。score_cast_func對value進行轉換的函數zrevrange(name, start, end, withscores=False, score_cast_func=float)同上,只不過集合默認為從大到小排序zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float)對應value值獲取其對應key以及value元素,默認value從小到大zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float)同上,只不過value默認是從大到小zscan(name, cursor=0, match=None, count=None, score_cast_func=float)獲取所有的value,默認value從小到大zcount(name, min, max)統計value在min以及max的元素個數zincrby(name, amount, value)對應name的集合中的value分數,每次都自增amountzrank(name, value)獲取集合name中的value排在第幾,導出從小到大的正序的索引號zrevrank(name, value)同上,只不過是從大到小的正序索引號zscore(name, key)獲取集合name中key對應的value值zrem(name, key)刪除集合name中的單個key值zremrangebyrank(name, min, max)刪除對應的索引元素(將其value進行從小到大進行排序)zremrangebyscore(name, min, max)刪除value范圍在min以及max之間的(將其value進行從小到大進行排序)

獲取元素的key以及對應value,具體操作:

r.zadd("names", {
"ma": 1, "nong": 2, "yan": 3}) # 新增元素,而且設置對應的key以及value
r.zcard("names") # 返回有序集合個數長度
r.zrange("names", 0, -1) # 取出集合names中所有元素的key
r.zrange("names", 0, -1, withscores=True) # 取出集合names中所有元素 正序 排序,有key以及value
r.zrevrange("names", 0, -1, withscores=True) # 同上,倒序操作
r.zrangebyscore("names", 1, 3, withscores=True) # 取出集合中的value范圍在1-3之間的,value按照從小到大輸出對應的key以及value
r.zrevrangebyscore("names", 1, 3, withscores=True) # 同上,從大到小的輸出
r.zscan("names") # 取出所有有序集合的元素
r.zscan_iter("names") # 獲取所有元素,這是一個迭代器
#具體操作如下:
for i in r.zscan_iter("names"): # 遍歷迭代器
print(i)

計數、自增、獲取索引以及刪除等具體操作:

r.zcount("names", 1, 3) # 統計value在1-3之間的元素個數,並且返回
r.zincrby("names", 2, "ma") # 將ma的value自增2
r.zscore("names", "ma") # 返回key對應的value
r.zrank("names", "ma") # 返回元素ma的下標(從小到大排序)
r.zrerank("names", "ma") # 返回元素ma的下標(從大到小排序)
r.zrem("names", "ma") # 刪除單個key
r.zremrangebyrank("names", 0, 2) # 刪除下標在0到2間的元素
r.zremrangebyscore("names", 1, 3) # 刪除value在1-3之間的元素

3. 實戰

結合python web開發
通過表單獲取redis的數據
通過普通連接或者連接池連接
連接成功之後獲取想要的數據傳回到表單即可

3.1 普通連接

調用一般的redis函數,或者自已封裝一個連接函數

def get_redis(config):
sentinels = config.get("sentinels", "")
cluster_tag = config.get("cluster_tag", "")
if all([sentinels, cluster_tag]):
sentinel = Sentinel(sentinels, socket_timeout=5)
REDIS = sentinel.master_for(cluster_tag, socket_timeout=5)
else:
REDIS = StrictRedis(host=config.get("host", "127.0.0.1"),
port=config.get("port", 6379))
return REDIS

3.2 連接池連接

一般企業都會有很清晰的流水線
如果劃分了dev以及生產環境,不同的redis集群配置放不同配置
這部分是setting的公共配置

REDIS_CACHES = {

'manongyanjiuseng': {

'type': 'sentinel',
'cluster_tag': 'manongyanjiuseng_test',
'host': [
("ip", 端口號),
("https://blog.csdn.net/weixin_47872288", 端口號),
("https://blog.csdn.net/weixin_47872288", 端口號),
],
'socket_timeout': 10,
'master': 1,
'db': 3
},
# 同理如上創建
}

公共類的函數都放在common.py中

import redis
from redis.sentinel import Sentinel
from redis import StrictRedis
# 初始化一個線程池
CONNECTION_POOL = {
}
# 定義連接的參數
def get_redis_connection(server_name='default'):
# 函數內部可改變函數外部的變量,所以定義global
global CONNECTION_POOL
if not CONNECTION_POOL:
CONNECTION_POOL = _setup_redis()
pool = CONNECTION_POOL[server_name]
if settings.REDIS_CACHES[server_name].get("type") == "sentinel":
return pool
return redis.Redis(connection_pool=pool)
def _setup_redis():
for name, config in settings.REDIS_CACHES.items():
if config.get("type") == "sentinel":
sentinel = Sentinel(config['host'], socket_timeout=config['socket_timeout'])
if config.get('master'):
pool = sentinel.master_for(
config["cluster_tag"],
redis_class=redis.Redis,
socket_timeout=config['socket_timeout']
)
else:
pool = sentinel.slave_for(
config["cluster_tag"],
redis_class=redis.Redis,
socket_timeout=config['socket_timeout']
)
else:
pool = redis.ConnectionPool(
host=config['host'],
port=config['port'],
db=config['db'],
socket_timeout=1
)
CONNECTION_POOL[name] = pool
return CONNECTION_POOL

在調用連接的時候通過如下:

# manong這個值是通過form表單傳入進去的
redis = get_redis_connection(manong)

  1. 上一篇文章:
  2. 下一篇文章:
相關文章
    没有相关文章
Copyright © 程式師世界 All Rights Reserved