Redis快取資料庫-快速入門

2023-03-08 18:00:35

Redis資料庫快速入門

一、Redis資料庫

介紹:

Redis:非關係型快取資料庫

  • nosql:非關係型資料庫

    • 沒有表,沒有表與表之間的關係,更不存在外來鍵
    • 儲存資料的形式為key:values的形式
    • c語言寫的服務(監聽埠),用來儲存資料的,資料是儲存在記憶體中,取值,放值速度非常快, 10w qps
  • 快取資料庫:

    • 資料儲存在記憶體中
    • 大部分時間用於快取,也可以長久儲存資料
  • redis速度為什麼這麼快:

    • 純記憶體操作
    • 網路模型使用的IO多路複用(可以處理的請求更多)
    • 6.x版本之前,單程序,單執行緒,不存在程序執行緒之間切換,更少消耗資源

1、redis的安裝與執行

版本選擇:

安裝:



redis需要了解的目錄結構:

  • redis-server :伺服器端啟動檔案
  • redis-cli:客服端啟動檔案
  • redis.windows-service.conf:預設使用的組態檔
    • bind 127.0.0.1 :伺服器端跑在的地址
    • port 6379 :佔用的埠號

啟動redis:

  • 方式一:將伺服器端新增至系統服務(電腦執行自動啟動)
    *
  • 方式二:cmd終端使用命令啟動
    • redis-server 指定組態檔 # 如果不指定,會預設

客服端連結redis:

  • cmd終端使用命令

    • 方式一:redis-cli 預設連結原生的6379埠

    • 方式二:redis-cli -h 地址 -p 埠

2、RESP圖形化操作檔案

可以使用軟體:

Redis Desktop Manager :開源的,原來免費,後來收費了  推薦用(mac,win,linux 都有)

-Qt5  qt是個平臺,專門用來做圖形化介面的 
    -可以使用c++寫
    -可以使用python寫  pyqt5  使用python寫圖形化介面 (少量公司再用)
    
-resp-2022.1.0.0.exe 一路下一步,安裝完啟動起來

-Redis Client  小眾

RESP操作redis:

二、pycharm操作redis

安裝模組:

使用pycharm操作redis,pycharm相當於使用者端,輸入redis命令即可對資料庫進行操作

# 下載模組:
	pip install redis
    
# 補充:django 中操作mysql,沒有連線池的,一個請求就是一個mysql連線
    -可能會有問題,並行數過高,導致mysql連線數過高,影響mysql效能
    -使用django連線池:https://blog.51cto.com/liangdongchang/5140039

1、Redis普通連線和連線池

普通連結:

普通連結是指,直接操作redis,每一次操作都會建立一條連結

# 匯入模組
from redis import Redis

# 範例化物件(後方引數填寫連結的地址和埠,還可以填寫其他引數)
conn = Redis(host='127.0.0.1', port=6379)

# 向redis中存放一個資料
conn.set('name', 'kangkang')

# 從redis中取出存放的資料(二進位制格式)
print(conn.get('name'))

# 操作完成,手動關閉,不然會一直佔用一條連結
conn.close()

連線池連線:

拿到一個Redis範例的連線池,避免每次建立、釋放連線的開銷,節省了每次連線用的時間,文中設定了最大10個。

POOL.py

# 1、使用單例模式(保證每次使用的都是同一個範例物件),設定連線池最大為10個
    import redis

    POOL = redis.ConnectionPool(
        # 最大連結
        max_connections=10,
        # 指定伺服器端地址
        host='127.0.0.1',
        prot=6379
    )

my_redis.py

# 匯入redis
from redis import Redis
# 匯入執行緒模組(模仿多執行緒並行)
from threading import Thread
# 匯入自己建立的單例
from script.pool import POOL


# 寫一個函數,在內部操作redis
def task():
    # 以後生成的物件都是POLL這一個範例化的物件
    conn = Redis(connection_pool=POOL)
    conn.set('name', 'kangkang')
    print(conn.get('name'))

if __name__ == '__main__':
    for i in range(100):
        t = Thread(target=task)
        t.start()

2、Redis資料型別

介紹:

redis 是key-value形式儲存

redis 資料放在記憶體中,如果斷電,資料丟失---》需要有持久化的方案

型別 介紹
字串(string) 用的最多,做快取;做計數器
列表(list) 常用於訊息佇列
字典(hash) 快取
集合(set) 去重
有序集合(zset) 排行榜

2、1.String型別

# 1、set(name, value, ex=None, px=None, nx=False, xx=False)
    ex:過期時間(秒)
    px:過期時間(毫秒)
    nx:如果設定為True,則只有name不存在時,當前set操作才執行, 值存在,就修改不了,執行沒效果
    xx:如果設定為True,則只有name存在時,當前set操作才執行,值存在才能修改,值不存在,不會設定新值
    
# 2、setnx(name, value) 
	等同於set('name','kangkang',nx=True)
    
# 3、setex(name,time,values)
	等同於set('name',10,'kangkang')
    
# 4、psetex(name,time_ms,values)
	conn.psetex('name',3000,'kangkang')
    
# 5、mset(*args,**kwargs)
	可以批次存入資料
	conn.mset({'name':'kangkang','age':18})
    
# 6、get(name)
	取值(單個)
	coon.get('name')
    
# 7、mget(keys, *args)
	批次取值(可以是列表)
	coon.mget('name','age')
	coon.mget(['name','age'])
    
# 8、getset(name, value)
	放置新的值進入(可以使用變數接收被替換的值)
   	res = coon.getset('name','jason')
	
# 9、getrange(key, start, end)
	按照指定key對應值的索引位置取值(按位元組取值)
	res = coon.gettrange('name',0 ,3)
  
# 10、settrange(name, offset, value)
	按照索引位置替換指定key對應的值(按照位元組)
 	coon.settrange('name',3,'bbb')

---- 位元位---操作----
# 11 setbit(name, offset, value)
# 12 getbit(name, offset)
# 13 bitcount(key, start=None, end=None)
---- 位元位---操作-----

# 14、bitop(operation, dest, *keys)
	獲取多個值,並將值做位運算,將最後的結果儲存至新的name對應的值
    
# 15、strlen(name)
	獲取指定key對應值的位數(按位元組)
	res = coon.strlen('name')

# 16、incr(self, name, amount=1)
	自增(預設自增:1,不支援含有浮點型別)
   	conn.incr('age')
    
# 17、incrbyfloat(self, name, amount=1.0)
	自增(支援小數)
  
# 18、decr(self, name, amount=1)
	自減
   
# 19、append(key, value)
	在指定key對應值的後面新增指定字元
	conn.append('name','NB')

2、2.List型別

from redis import Redis

conn = Redis(host='127.0.0.1', port=6379)

#  1、lpush(name, values)
    # 鍵為key,值為list(引數位置在前生成資料的索引位置就在後)
    conn.lpush('gender', 'male', 'female')

#  2、rpush(name, values)
    # 鍵為key,值為list(引數位置在前生成資料的索引位置就在前)
    conn.rpush('hobby', 'read', 'run')

# 3、lpushx(name, value)
    # 向列表插入一個值(有對應的key就插入到列表的頭部,沒有就不操作)
    conn.lpushx('gender', 'female')

# 4、rpushx(name, value)
    # 向列表插入一個值(有對應的key就插入到列表的尾部部,沒有就不操作)
    conn.rpushx('hobby', 'ball')

# 5、llen(name)
    # 判斷列表內有多少個資料
    print(conn.llen('hobby'))

# 6、linsert(name, where, refvalue, value))
    # name:插入到哪個列表
    # where:插入到指定值的前或後before:前/after:後
    # refavalue:插入到哪個值
    # value:插入的值
    # 向列表內插入資料
    conn.linsert('hobby', 'after', 'run', 'go')

# 7、lset
    # 向指定的索引位置插入一個值
    conn.lset('hobby', 1, 'sleep')

# 8、lrem
    # 刪除指定的值,可以指定刪除的數量,填 0 全部刪除,負數從後面刪除
    conn.lrem('hobby', 0, 'aaaa')

# 9、lpop(name)
    # 從頭部彈出一個值,可以接收
    res = conn.lpop('hobby')
    print(res)

# 10、rpop(name)
    # 從尾部彈出一個值,可以接收
    res = conn.rpop('hobby')
    print(res)

# 11、lindex(name, index)
    # 按照索引位置取值
    res = conn.lindex('hobby', 1)
    print(res)

# 12、lrange(name, start, end)
    # 按照索引位置,範圍取值,第二個引數填負數取全部
    res = conn.lrange('hobby', 0, -1)
    print(res)

# 13、ltrim(name, start, end)
    # 修剪,留下索引位置內的資料
    res = conn.ltrim('hobby', 1, 2)
    print()

# 14、rpoplpush(src, dst)
    # 提供兩個列表,將第一個列表的值被彈出,加入到第二個列表內
    conn.lpush('gender', 'male')
    conn.rpoplpush('gender', 'hobby')

# 15、blpop(keys, timeout)
    # 可做訊息佇列,彈出資料(從左向右)
    res = conn.blpop('hobby')
    print(res)

# 16、brpop(keys, timeout)
    # 可做訊息佇列,彈出資料(從右向左)
    res = conn.brpop('hobby')
    print(res)

# 17、brpoplpush(src, dst, timeout=0)
    # 將彈出的資料加入到兩一個列表中
    res = conn.brpoplpush('hobby','gender')
    print(res)

conn.close()

2、3.Hash型別

import redis

conn = redis.Redis()

# 1、hset(name, key, value)
    # 設定一個key,value值為字典
    conn.hset('userinfo','name','lqz')
    # 這種方法可以一次寫入多個鍵值對
    conn.hset('userinfo',mapping={'age':19,'hobby':'籃球'})

# 2、hmset(name, mapping)
    # 批次設定,被棄用了,以後都使用hset
    conn.hmset('userinfo2',{'age':19,'hobby':'籃球'})

# 3、hget(name,key)
    # 取值
    res = conn.hget('userinfo', 'name')
    print(res)

# 4、hmget(name, keys, *args)
    # 批次取值
    res = conn.hmget('userinfo', ['name', 'age'])
    # 第二種寫法
    res = conn.hmget('userinfo', 'name', 'age')
    print(res)

# 5、hgetall(name)
    # 一次性取出所有的值(慎用,資料量龐大的話會引起司機、宕機)
    res=conn.hgetall('userinfo')
    print(res)

# 6、hlen(name)
    # 獲取鍵值對的數量
    res=conn.hlen('userinfo')
    print(res)

# 7、hkeys(name)
    # 一次性獲取所有key值
    res=conn.hkeys('userinfo')
    print(res)

# 8、hvals(name)
    # 一次性獲取所有value值
    res=conn.hvals('userinfo')
    print(res)

# 9、hexists(name, key)
    # 判斷value值是否存在,返回1/0
    res = conn.hexists('userinfo', 'name')
    res = conn.hexists('userinfo', 'name1')
    print(res)

# 10、hdel(name,*keys)
    # 刪除對應的value值
    res = conn.hdel('userinfo', 'age')
    print(res)

# 11、hincrby(name, key, amount=1)
    # 指定欄位自增,預設自增1
    conn.hincrby('userinfo', 'age', 2)


# 12、hincrbyfloat(name, key, amount=1.0)
    # 自增,支援小數

# 13、hgetall(name)
    # 一次性取出所有value的鍵值對
    # 插入一批資料
    for i in range(1000):
        conn.hset('hash_test','id_%s'%i,'雞蛋_%s號'%i)
    res=conn.hgetall('hash_test')   # 可以,但是不好,一次性拿出,可能佔很大記憶體
    print(res)


# 14、hscan(name, cursor=0, match=None, count=None)   
    # 按照遊標位置取值
    res = conn.hscan('hash_test', cursor=0, count=5)
    print(len(res[1])) #(數位,拿出來的10條資料)   數位是下一個遊標位置



# 15、hscan_iter(name, match=None, count=None)
    # 類似生成器,一次只拿出指定數量的值
    res = conn.hscan_iter('hash_test', count=10)
    print(res)  # generator 只要函數中有yield關鍵字,這個函數執行的結果就是生成器 ,生成器就是迭代器,可以被for迴圈
    for i in res:
        print(i)

conn.close()

4、通用操作

import redis

conn = redis.Redis()

# 1、delete(*names)
    # 刪除指定的key,一次刪除多個
    conn.delete('name', 'userinfo2')
    conn.delete(['name', 'userinfo2'])  # 不能用它
    conn.delete(*['name', 'userinfo2'])  # 可以用它,打散


# 2、exists(name)
    # 判斷redis中是否存在指定的key(返回 0/1)
    res=conn.exists('userinfo')
    print(res)


# 3、keys(pattern='*')
    # 查詢value的key值中是否存在指定的key,返回對應的value(支援簡單的正則)
    res=conn.keys('w?e')  #  ?表示一個字元,   * 表示多個字元
    print(res)


# 4、expire(name ,time)
    # 設定過期時間
    conn.expire('userinfo',3)

# 5、rename(src, dst)
    # 重新命名
    conn.rename('hobby','hobby111')

# 6、move(name, db)
    # 更改儲存資料的庫
    conn.move('hobby111',8)


# 7、randomkey()
    # 隨機獲得一個key
    res = conn.randomkey()
    print(res)

# 8、type(name)
    # 判斷資料的型別
    print(conn.type('userinfo'))
    print(conn.type('age'))

conn.close()

3、Redis管道

什麼是管道:

管道是指,將多條redis操作放在管道內同時執行,管道也是一種事務的操作,可以作用於敏感,重要的資料

ridis支援事務嗎:

redis的事務基於管道,只有單範例才支援事務

ridis管道的使用:

# 引入redis
import redis

# 範例化redis物件
conn = redis.Redis()

# 範例化管道
p = conn.pipeline(transaction=True)

# 開啟管道(類似於開啟事務)
p.multi()
# 模擬張三給李四100元
p.decr('zhangsan', 100)
# 模擬李四賬戶增加100元
p.incr('lisi', 100)
# 啟動管道(類似於提交事務)
p.execute()

# 關閉
p.close()

三、Django操作Redis

1、自定義包方案

這種方案所有的框架都可以使用

- 1、第一步:建立一個pool.py檔案(匯入rides,並範例化物件,生成連線池)
	import Redis
	# 範例化物件,設定連線池最大數量為100
	POOL = Redis.CoonectionPool(max_connections=100)
    
- 2、第二步:在以後需要使用的地方直接匯入使用即可
    from pool import POOL 
    from redis import Redis
    conn = Redis(connections=POOL)
    conn.set('name','kangkang')
    res = conn.get('name')

2、將Redis設定為Django快取[推薦使用]

需要安裝模組,設定settings檔案,以後直接作為Django內建快取使用

- 安裝模組:
	pip install django-redis
    
- settings.py 中設定:
    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379",  # 地址和埠
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
                "CONNECTION_POOL_KWARGS": {"max_connections": 100}  # 連線池
                 # "PASSWORD": "123",  # 密碼,沒有的話不用設定
            }
        }
    }
    

- 在需要使用的地方直接使用即可(但是隻能支援記憶體的操作)
    在使用redis的地方:cache.set('count',  res+1)  # 可以存入任何型別的資料
    # 底層做了pickle序列化 

3、使用第三方模組

直接使用django-redis模組


from django_redis import get_redis_connection

def test_redis(request):
    conn=get_redis_connection()
    print(conn.get('count'))
    return JsonResponse()