redis基本使用

文章目录

  • redis介绍和安装
  • redis配置文件启动
  • pthon操作普通连接和连接池
  • 最好写成单例
  • 字符串操作
  • hash类型操作
  • list类型操作
  • redis的其他操作
  • django只要Redis
  • 使用缓存案例

redis介绍和安装

redis 是什么?
-非关系型数据库:redis,mongodb,es,clickhouse,influxDB
no sql: not only sql

-关系型数据库:mysql,oracle,postgrasql,sqlserver,sqlite
-去IOE ,国产化
IBM:服务器
Oracle:数据库 达梦
EMC:存储

-redis 到底是什么?
    	redis是一个key-value存储系统【软件】,用c语言写的,c/s架构的软件,纯内存存储,可以持久化【断电数据可以恢复】
   value:有5钟数据类型
   string:字符串
    hash:字典
    list:列表
    set:集合
    zset:有序集合

redis为什么这么快?
- qps :10w 6w左右
-1 纯内存操作,避免了io
-2 使用了io多路复用的网络模型–(epoll)
-3 数据操作是单线程单进程—【没有锁操作,没有线程间切换】

安装redis
-redis开源项目,社区不支持win
-使用的epoll模式,不能再win上运行的
-微软团队—》基于人家源码,修改+编译—》安装包–》可以装在win上
-最新:最新7.x
# win平台最新只有
-最新5.x版本 https://github.com/tporadowski/redis/releases/
-最新3.x版本 https://github.com/microsoftarchive/redis/releases
# 下载:Redis-x64-5.0.14.1.msi,一路下一步

安装完成之后 会自己做成系统服务 直接启动即可
redis基本使用_第1张图片

客户端安装
-cmd窗口
-redis-cli -h 127.0.0.1 -p 6379
-redis-cli
可以连接图形化页面的软件
-resp
-安装链接
-Navicate 16
链接即可
-…

redis配置文件启动

# 配置成服务---》启动停止服务即可

# 通过命令启动停止
	# 安装目录下,重要的可执行文件
	redis-cli  :客户端   等同于mysql 的 mysql
    redis-server :服务端等同于mysql 的 mysqld
    #重要的配置文件---》mysql 的 my.ini
    	-redis.windows-service.conf
        	- databases 16
            - port 6379
            - bind 127.0.0.1
            
            
   # 启动redis-->使用配置文件
	redis-server  配置文件路径
    redis-server redis.windows-service.conf
    
    
# 关闭
	-服务中点停止
    -cmd客户端链接上:执行   shutdown
    
# redis数据是存在内存中得
	-重启redis服务,关机---》数据都会丢失
    -咱们不会丢 redis.windows-service.conf 已经写了持久化方案
    	-从内存把数据保存到硬盘上的过程称之为持久化

pthon操作普通连接和连接池

# 普通连接
from redis import Redis

comm = Redis(host="localhost",
             port=6379,
             db=0,
             decode_responses=True) # decode_responses 中文名需要转码则是加上这个参数
                                    # print(res.decode(encoding='utf-8')) 手动转码
                                    # print(str(res,encoding='utf-8'))

res = comm.get('name') # 如果是中文 需要转码

print(res)

comm.close()


# 链接池的创建
import redis
# 创建池 max_connections 最大链接数  decode_responses 中文转码
# 创建池--->保证pool是单例的---》全局只有一个pool对象实例
pool = redis.ConnectionPool(max_connections=11, host='localhost', port=6379, decode_responses=True)

comm = redis.Redis(connection_pool=pool)

res = comm.get('name')  # 如果是中文 需要转码

print(res)

comm.close()

最好写成单例

不写成单例 每次链接就会生成一个链接池

# 单例写法
# 创建一个文件
import redis
POOL = redis.ConnectionPool(max_connections=11, host='localhost', port=6379, decode_responses=True)

# 使用的时候
from s1 import POOL
import redis
from threading import Thread

def task():
    # 每次执行函数就不用重新创建连接池了
    conn = redis.Redis(connection_pool=POOL)
    res = conn.get('name')
    print(res)
    conn.close()  # 把链接放回到连接池

l = []
for i in range(3):
    t = Thread(target=task)
    t.start()
    l.append(t)

for t in l:
    t.join()

print('结束了')

字符串操作

# key  value  ex 设置过期时间 px 设置毫秒过期时间  nx 值不存在设置 xx 值存在设置
# 1 set(name, value, ex=None, px=None, nx=False, xx=False)  设置值
conn.set('hobby', '篮球')
# # 带过期时间
conn.set('age', '19', ex=3)
conn.set('age', '19', px=3000)

# 如果key存在才设置或不存在才设置
# nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
# xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
conn.set('age', 19, nx=True)
conn.set('age', 99, nx=True)
conn.set('age', 99, xx=True)
conn.set('yy', 99, xx=True)

# 2 setnx(name, value)  存在就不改了
conn.setnx('age', 999)  # 等同于 conn.set('age',19,nx=True)

# 3 psetex(name, time_ms, value) # 设置值进去并且加上过期时间 时间是毫秒
conn.psetex('xxx', 3000, '阿斯顿发') 
conn.setex('xxx', 3, '阿斯顿发')

# 4 mset(*args, **kwargs) 批量设置字典的形式
conn.mset({'name':'yyy','age':888,'height':180})

# 5 get(name) # 获取一个
res=conn.get('name')
print(res)

# 6 mget(keys, *args) 获取多个值
res=conn.mget('name','age','height')
#'name','age','height'----> name   [age,height]--->[name,age,height]
# ['name','age','height']-->['name','age','height']--->[name,age,height]
# res=conn.mget(['name','age','height'])
# print(res)

# 7 getset(name, value) 取值出来 在重新放一个新值进去
res = conn.getset('name', '彭于晏')
# 先get,再set和  getset区别? 一直io操作
print(res)

# 8 getrange(key, start, end)  数字指的是字节长度 切片取值 但是中文不能切开 会保错
# 字符:  a   b  你   中  国
# 字节:  8个bit位一个字节,存 一个字母字符 用一个字节就够了  但存中文--》utf-8---》需要3个字节存一个字符
res = conn.getrange('name', 0, 2)  # 前闭后闭区间
print(res)
print(str(res, encoding='utf-8'))

s = 'lqz?厉害'
print(len(s))
print(len(bytes(s, encoding='utf-8')))
print(len(bytes(s, encoding='gbk')))

# 9 setrange(name, offset, value)  # 设置字节 在value前面设置值
conn.setrange('name', 3, 'eeee')

#### 比特位操作####
# 10 setbit(name, offset, value)
# print(conn.getbit('name',3))
# 11 getbit(name, offset)
# 12 bitcount(key, start=None, end=None)
# 13 bitop(operation, dest, *keys)
#### 比特位操作####


# 14 strlen(name)
print(conn.strlen('name')) # 统计的是字节长度

# 15 incr(self, name, amount=1) 和 incrby 两个一样的
# 自增 什么数字是增加的步长
#incrby
conn.incrby('age')  # 文章阅读量  计数器  单线程 不会有并发安全问题
conn.incrby('age',3)

# 16 incrbyfloat(self, name, amount=1.0) 小数增加

# 17 decr(self, name, amount=1) 自减 数字为步长
conn.decrby('age',2)

# 18 append(key, value) 字符串相加
conn.append('age',8888)
conn.append('hobby','很好')

conn.close()
'''
你需要掌握的
get
set
setex  
getrange
setrange
strlen
append
'''

hash类型操作

import redis

POOL = redis.ConnectionPool(max_connections=11, host='localhost', port=6379, decode_responses=True)

conn = redis.Redis(connection_pool=POOL)
# 1 hset(name, key, value)  设置值 和批量设置 加上mapping指定一个字典
conn.hset('userinfo','name','lqz')
conn.hset('userinfo','age',18)
# userinfo = {'name':'huang','age':18} 这样的形式展现
conn.hset('userinfo2', mapping={'name': '刘亦菲', 'age': 19, 'hobby': '抽烟'})


# 3 hget(name,key) 获取单个值
print(conn.hget('userinfo2', 'hobby'))

# 4 hmget(name, keys, *args) 获取多个值 可以是元组 列表
print(conn.hmget('userinfo2', ('hobby', 'name', 'age')))
print(conn.hmget('userinfo2', ['hobby', 'name', 'age']))

# 5 hgetall(name)   慎用 因为一下子取出来内存可能过大
res = conn.hgetall('userinfo2')
print(res)

# 6 hlen(name) 统计有多少个值
print(conn.hlen('userinfo2'))

# 7 hkeys(name) 获取所有的key
print(conn.hkeys('userinfo2'))

# 8 hvals(name) 获取所有的 value
print(conn.hvals('userinfo2'))

# 9 hexists(name, key) 判断有没有这个key值
print(conn.hexists('userinfo2','hobby1'))

# 10 hdel(name,*keys) 删除一个值 返回的是删除的条数
res=conn.hdel('userinfo2','hobby')
print(res)


# 11 hincrby(name, key, amount=1) 字典自增
conn.hincrby('userinfo2','age')

# 12 hincrbyfloat(name, key, amount=1.0) 可以通过amount 来设置自增多少
conn.hincrbyfloat('userinfo2', 'age', amount=1.2)

# 造数据
for i in range(1000):
    conn.hset('map_demo',i,'鸡蛋_%s'%i)

# 一次性取出来
res=conn.hgetall("map_demo")
print(res)

# 一点点取---》取的数量不准确(上下相差一点点),下次取值取决于上次的结果---》不单独使用
res=conn.hscan('map_demo',cursor=0,count=20)
print(res) # (数字,{数据})
print(len(res[1]))

# cursor值是从那个开始取 count 一次取多少条数据 取的数量不准确(上下相差一点点),下次取值取决于上次的结果---》不单独使用
res=conn.hscan('map_demo',cursor=320,count=10)
print(res) # (数字,{数据})

# 14 hscan_iter(name, match=None, count=None) # 取出所有数据等同于 hgetall,但是是一点点取(count的值),一点点用
# 内部是生成器
res=conn.hscan_iter('map_demo',count=10)  # 这个数字并不是取10条,而是 每次取10条,把所有都取尽
print(res) # generator
for item in res:
    print(item)

# 内部具体如何实现---》内部使用了hscan
# res=conn.hscan_iter('map_demo',count=10)
# 内部通过调用 hscan实现 每次取10条,用完再继续取10条,直到所有数据都取完

'''
 掌握
hset
hget
hmget
hlen
hincr
hscan_iter
'''

list类型操作

import redis

POOL = redis.ConnectionPool(max_connections=11, host='localhost', port=6379, decode_responses=True)

conn = redis.Redis(connection_pool=POOL)

# 1 lpush(name, values)
# resp:上面是左,下面是右
conn.lpush('girls', '刘亦菲')  # 从左侧插入值
conn.lpush('girls', '迪丽热巴')  # 从左侧插入值

# 2 rpush(name, values) 表示从右向左操作
conn.rpush('girls','李清照')

# 3 lpushx(name, value)
conn.lpushx('girls','lqz')  #girls key 要存在,如果不存在,就放不进去
conn.lpushx('boys','lqz')  #girls 要存在,如果不存在,就放不进去
conn.lpush('boys','lqz')   # 重新创建


# 4 rpushx(name, value) 表示从右向左操作
conn.rpushx('girls','小红')

# 5 llen(name) 统计长度
print(conn.llen('girls'))

# 6 linsert(name, where, refvalue, value))
# where='after' 指定前面还是后面加值 refvalue 在那个值加前还是后 value 添加的值
conn.linsert('girls', where='after', refvalue='刘亦菲', value='上海刘亦菲')
conn.linsert('girls', where='before', refvalue='刘亦菲', value='山东刘亦菲')

# 7 lset(name, index, value) 修改值 数字是索引位置 后面是修改的值
conn.lset('girls', 1, 'lqz')  # 从0 开始计算
conn.lset('girls', 3, 'lqz')  # 从0 开始计算

# 8 r.lrem(name, value, num)
conn.lrem('girls', 1, 'lqz')  # 从左往右删1个
conn.lrem('girls', -1, 'lqz')  # 从右往左删1个
conn.lrem('girls', 0, 'lqz')  # 所有都删除

# 9 lpop(name) 左边弹出一个值
print(conn.lpop('girls'))

# 10 rpop(name) 表示从右向左操作
print(str(conn.rpop('girls'), encoding='utf-8'))

# 11 lindex(name, index)
res = conn.lindex('girls', 1)  # 按索引取值,从0开始
print(res)

# 12 lrange(name, start, end) 取索引0-1这两个值
res=conn.lrange('girls',0,1) # 前闭后闭区间
print(res)

# 13 ltrim(name, start, end) 只保存开始和结束的值
# res =  # 前闭后闭 只保留索引开始和结束的值  以外的全部删除
conn.ltrim('6666',1,2)

# 14 rpoplpush(src, dst) #两个列表 ,从第一个列表的右侧弹出,放到第二个列表的左侧


# 15 blpop(keys, timeout) # 阻塞式弹出--》可以做消息队列---》分布式
res=conn.blpop('boys',timeout=5)
print(res)

# 16 r.brpop(keys, timeout),从右向左获取数据

# 右边的列表弹出一个值 放到左边的列表中 timeout 设置时间 时间到了返回None
# 17 brpoplpush(src, dst, timeout=0)


redis的其他操作

from redis import Redis

conn = Redis(decode_responses=True)

# delete(*names) 删除多个
# conn.delete('name','age')

# exists(name) 判断数据是否在里面
# res=conn.exists('userinfo1','name','height')
# print(res)


# keys(pattern='*')
# 查找key 可以是多个

# res=conn.keys('u*')
# print(res)


# expire(name ,time)  设置过期时间
# conn.expire('girls',3)


# rename(src, dst) # 重命名
# conn.rename('hobby','bobby1')

# move(name, db)) # 转移库
# conn.move('bobby1',2)

# randomkey() 随机取出一个数据
# print(conn.randomkey())

# type(name)
print(conn.type('height')) #string
print(conn.type('map_demo')) #hash

django只要Redis

# 第一种方式 使用第三方redis
# 创建一个文件
import redis

POOL = redis.ConnectionPool(max_connections=11, host='localhost', port=6379, decode_responses=True)

conn = redis.Redis(connection_pool=POOL)

# 视图类
from scripts.redis_demo.dome import POOL
# CommonListModelMixin 继承了ListModelMixin
class RedisView(GenericAPIView,CommonListModelMixin):

    def get(self, request, *args, **kwargs):
        conn = redis.Redis(connection_pool=POOL)
        conn.incrby('count',1)
        count=conn.get('count')
        return APIResponse(msg='您是第%s个访问的' % count)


# 第二种方式:
# 1 安装 pip install django-redis

# 2 配置文件配置
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",
        }
    }
}

# 视图类
from django_redis import get_redis_connection
class RedisViews(GenericAPIView,CommonListModelMixin):

    def get(self, request):
        conn = get_redis_connection() # 从池中获取一个链接
        conn.incrby('count')
        count = conn.get('count')
        return APIResponse(msg='您是第%s个访问的' % count)


# 方式三:django的缓存
# django内置的,可以直接操作缓存---》缓存的位置--》内存--》只要项目一重启,数据就没了
# 后期,我们要把缓存数据,放到 redis中 ,redis可以持久化,项目停止,但redis还运行,数据就不会丢

# 只要在配置文件中,如下配置,以后只要使用 cache.set  和 cache.get 通过都是去redis设置和取
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",
        }
    }
}
# cache.set()  设置缓存
# cache.get()  获取缓存


## 以后再django中,可以直接使用
cache.set 和cache.get  操作redis,用它做缓存 ---》非常简单

## 重点:
	-优势:redis 分数据类型, 只能设置5种数据类型
   	-django的缓存来讲 ,不限制类型,可以放python的任意类型
    
    -django的缓存来讲,cache.set('redis的key','不区分类型:放python的任意类型')  # person
    -cache.get('userinfo')
    -django cache 底层是基于: 把你存储的类型---》使用pickle序列化--bytes格式---》当redis的字符串形式存到redis中
    
    
    -以后咱们做redis的操作,可以直接使用django的缓存, 不需要考虑类型


使用缓存案例

from rest_framework.mixins import ListModelMixin
from rest_framework.views import APIView
from utils.common_logger import logger
from django.core.cache import cache

class HomeView(GenericViewSet, CommonListModelMixin):
    queryset = Banner.objects.all().filter(is_delete=False, is_show=True).order_by('orders')[:settings.BANNER_COUNT]
    serializer_class = SerializerBanner

    def list(self, request, *args, **kwargs):
        # 缓存中如果没有,就去数据中查---》放入缓存
        # 先查缓存,缓存中有直接返回
        banner_list = cache.get('banner_list')  # 列表类型
        if not banner_list:
            # 缓存中没有:去数据库查 ,查完序列化   ListModelMixin.list
            logger.info('走了数据库')
            res = ListModelMixin.list(self, request, *args, **kwargs)
            banner_list = res.data
            cache.set('banner_list', banner_list)
        return APIResponse(results=banner_list)

# 路由
http://127.0.0.1:8000/api/v1/home/banner/

你可能感兴趣的:(redis,数据库,缓存)