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,一路下一步

安装完成之后 会自己做成系统服务 直接启动即可

客户端安装

-cmd窗口

-redis-cli -h 127.0.0.1 -p 6379

-redis-cli

可以连接图形化页面的软件

-resp

-安装链接

-Navicate 16

链接即可

-...

redis配置文件启动

python 复制代码
# 配置成服务---》启动停止服务即可

# 通过命令启动停止
	# 安装目录下,重要的可执行文件
	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操作普通连接和连接池

python 复制代码
# 普通连接
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()

最好写成单例

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

python 复制代码
# 单例写法
# 创建一个文件
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('结束了')

字符串操作

python 复制代码
# 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类型操作

python 复制代码
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类型操作

python 复制代码
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的其他操作

python 复制代码
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

python 复制代码
# 第一种方式 使用第三方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的缓存, 不需要考虑类型

使用缓存案例

python 复制代码
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/
相关推荐
小蜗牛慢慢爬行36 分钟前
如何在 Spring Boot 微服务中设置和管理多个数据库
java·数据库·spring boot·后端·微服务·架构·hibernate
hanbarger39 分钟前
nosql,Redis,minio,elasticsearch
数据库·redis·nosql
微服务 spring cloud1 小时前
配置PostgreSQL用于集成测试的步骤
数据库·postgresql·集成测试
先睡1 小时前
MySQL的架构设计和设计模式
数据库·mysql·设计模式
弗罗里达老大爷1 小时前
Redis
数据库·redis·缓存
别这么骄傲2 小时前
lookup join 使用缓存参数和不使用缓存参数的执行前后对比
缓存
仰望大佬0072 小时前
Avalonia实例实战五:Carousel自动轮播图
数据库·microsoft·c#
学不透java不改名2 小时前
sqlalchemy连接dm8 get_columns BIGINT VARCHAR字段不显示
数据库
一只路过的猫咪2 小时前
thinkphp6使用MongoDB多个数据,聚合查询的坑
数据库·mongodb