• Redis数据类型


    1.String(字符串)

    在任何一种编程语言中,字符串都是最基础的数据结构,在Redis中String是可以修改的称之为:动态字符串(简称SDS)

    Redis的内存分配机制:

            - 当字符串的长度小于1MB时,每次扩容都是加倍现有的空间

            - 如果字符串长度超过1MB时,每次扩容时只会扩展1MB空间

    ps:这样既保证了内存空间够用,也不会造成内存的浪费,字符串最大长度为512MB

    1. import redis
    2. conn = redis.Redis()
    3. # 1 set(name, value, ex=None, px=None, nx=False, xx=False)
    4. # ex,过期时间(秒)
    5. # px,过期时间(毫秒)
    6. # nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
    7. # xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
    8. # conn.set('name','abc') # value 只能是字符串或byte格式
    9. # conn.set('name','abc',ex=3) # ex 是过期时间,到3s过期,数据就没了
    10. # conn.set('name','abc',px=3000) # px 是过期时间,到3s过期,数据就没了
    11. # conn.set('age',18,nx=True) # redis 实现分布式锁
    12. # conn.set('hobby', '足球', xx=False) # hobby存在操作
    13. # 2 setnx(name, value) 就是:set nx=True
    14. # conn.setnx('hobby1','橄榄球')
    15. # 3 psetex(name, time_ms, value) 本质就是 set px设置时间
    16. # conn.psetex('name',3000,'abc')
    17. # 4 mset(*args, **kwargs) 传字典批量设置
    18. # conn.mset({'name':'xxx','age':19})
    19. # 5 get(name) 获取值,取到是bytes格式 ,指定:decode_responses=True,就完成转换
    20. # print(conn.get('name'))
    21. # print(str(conn.get('name')[:3],encoding='utf-8'))
    22. # 5 mget(keys, *args) #批量获取
    23. # res=conn.mget('name','age')
    24. # res=conn.mget(['name','age'])
    25. # print(res)
    26. # 6 getset(name, value) # 先获取,再设置
    27. # res=conn.getset('name','cba')
    28. # print(res)
    29. # 7 getrange(key, start, end) # 取的是字节,前闭后闭区间
    30. # res=conn.getrange('name',0,1)
    31. # print(res)
    32. # 8 setrange(name, offset, value) # 从某个起始位置开始替换字符串
    33. # conn.setrange('name', 1, 'xxx')
    34. # 9 setbit(name, offset, value)
    35. # conn.setbit('name',1,0) # 00000000 00000000 00000000
    36. # res=conn.get('name')
    37. # print(res)
    38. # 10 getbit(name, offset)
    39. # res=conn.getbit('name',1)
    40. # print(res)
    41. # 11 bitcount(key, start=None, end=None)
    42. # print(conn.bitcount('name',0,3)) # 3 指的是3个字符
    43. # 12 strlen(name) # 统计字节长度
    44. # print(conn.strlen('name'))
    45. # print(len('abc胡')) # len 统计字符长度
    46. # 13 incr(self, name, amount=1) # 计数器
    47. # conn.incr('age',amount=3)
    48. # 14 incrbyfloat(self, name, amount=1.0)
    49. # 15 decr(self, name, amount=1)
    50. # conn.decr('age')
    51. # 16 append(key, value) # 在后面追加
    52. # conn.append('name','nb')
    53. conn.close()

    2.list(列表)

    Redis的list和java中的LinkedLIst很像,底层都是一种链表结构,list的插入和删除操作非常快,时间复杂度为0(1),不像数组结构插入、删除操作需要移动数据

    当数据量较少的时候它的底层存储结构为一块连续内存,称之为ziplist(压缩列表),它将所有的元素紧挨着存储,分配的是一块连续的内存;当数据量较多的时候将会变成quicklist(快速链表)结构

    redis3.2之后就改用ziplist+链表的混合结构,称之为quicklist(快速链表)

    \(\bullet\) list应用场景它是按照插入顺序排序的列表:

            - 消息队列:lpop和rpush或者lpush和rpop能实现队列的功能

            - 朋友圈的点赞列表、评论列表、排行榜:lpush命令和lrange命令能实现最新列表的功能,每一次通过push命令往列表里插入新的元素,然后通过lrange命令读取最新的元素列表

    1. import redis
    2. conn = redis.Redis(decode_responses=True)
    3. # 1 lpush(name,values) 从左侧插入 [小明 小红 小张 小鹏]
    4. # conn.lpush('girls','小红')
    5. # conn.lpush('girls','小明')
    6. # conn.rpush('girls','小张') # 从右侧插入
    7. # conn.rpush('girls','小鹏')
    8. # 2 lpushx(name,value) 只有name已经存在时,值添加到列表的最左边
    9. # conn.lpushx('girls','小丽')
    10. # conn.lpushx('boys','小刚')
    11. # 3 rpushx(name, value) 表示从右向左操作
    12. # 4 llen(name)
    13. # res=conn.llen('girls')
    14. # print(res)
    15. # 5 linsert(name, where, refvalue, value))
    16. # conn.linsert('girls', where='after', refvalue='小红', value='李清照')
    17. # conn.linsert('girls', where='before', refvalue='小红', value='李清照')
    18. # 6 lset(name, index, value)
    19. # conn.lset('girls',0,'xx')
    20. # 7 lrem(name,count ,value) # count放数字,可以写负数,表示从右往前删除 0 表示全删
    21. # conn.lrem('girls',0,'李清照')
    22. # 8 lpop(name)
    23. # res=conn.lpop('girls')
    24. # res=conn.rpop('girls')
    25. # print(res)
    26. # 9 lindex(name, index)
    27. # res=conn.lindex('girls',2)
    28. # print(res)
    29. # 10 lrange(name, start, end) 前闭后闭
    30. # res=conn.lrange('girls',0,2)
    31. # print(res)
    32. # 11 ltrim(name, start, end) 修建
    33. # res=conn.ltrim('girls',1,2)
    34. # 12 rpoplpush(src, dst)
    35. # conn.rpoplpush('girls','boys')
    36. # 13 blpop(keys, timeout) 阻塞式弹出,如果列表中没有值,会阻塞在这,直到有值,再弹出,它可以做消息队列,做分布式的系统
    37. # res=conn.blpop('boys',timeout=3)
    38. # print(res)
    39. # 14 brpoplpush(src, dst, timeout=0)
    40. # 15 自定义增量迭代
    41. # res=conn.lrange('girls',0,conn.llen('girls'))
    42. # print(res)
    43. conn.close()

    3.hash(字典)

    Redis中的Hash和Java的HashMap更加相似,都是数组+链表的结构,当发送hash碰撞时将会把元素追加到链表上,要注意的是在Redis的Hash中value只能是字符串

    Hash和String都可以用来存储用户信息,但不同的是Hash可以对用户信息的每个字典单独存储;

    String存的是用户全部信息经过序列化后的字符串,如果想要修改某个用户字段必须将用户信息字符串全部查询出来,解析成响应的用户信息对象,修改完后在序列化成字符串存入

    Hash可以只对某个字段修改,从而节约网络流量但是hash内存占用要大于String

    \(\bullet\) 应用场景:

            - 购物车:hset[key] [field] [value],可以实现以用户id为field,商品数量为value,恰好构成了购物车的三要素

            - 存储对象:hash类型的(key,field,value)的结构与对象的(对象id,属性,值)的结构相似,也可以用来存储对象

    1. import redis
    2. conn = redis.Redis(decode_responses=True)
    3. # 1 hset(name, key, value)
    4. # conn.hset('userinfo', 'name', '彭于晏')
    5. # conn.hset('userinfo', 'age', '32')
    6. # conn.hset('xx',mapping={'name':'xxx','hobby':'篮球'})
    7. # 2 hmset(name, mapping) 弃用了
    8. # conn.hmset('yy',{'a':'a','b':'b'})
    9. # 3 hget(name,key)
    10. # res=conn.hget('userinfo','age')
    11. # print(res)
    12. # 4 hmget(name, keys, *args)
    13. # res=conn.hmget('userinfo',['name','age'])
    14. # print(res)
    15. # 5 hgetall(name) 慎用,可能会造成 阻塞 尽量不要在生产代码中执行它
    16. # res=conn.hgetall('userinfo')
    17. # print(res)
    18. # 6 hlen(name)
    19. # res=conn.hlen('userinfo')
    20. # print(res)
    21. # 7 hkeys(name)
    22. # res=conn.hkeys('userinfo')
    23. # print(res)
    24. # 8 hvals(name)
    25. # res=conn.hvals('userinfo')
    26. # print(res)
    27. # 9 hexists(name, key)
    28. # res=conn.hexists('userinfo','name')
    29. # print(res)
    30. # 10 hdel(name,*keys)
    31. # conn.hdel('userinfo','age')
    32. # 11 hincrby(name, key, amount=1)
    33. # conn.hincrby('userinfo','age')
    34. # 12 hincrbyfloat(name, key, amount=1.0)
    35. # conn.hincrbyfloat('userinfo','age',5.44)
    36. ## 联合起来讲:不建议使用hgetall,分片取值
    37. # 分批获取 生成器应用在哪了?
    38. # 13 hscan(name, cursor=0, match=None, count=None)
    39. # hash类型没有顺序---》python字典 之前没有顺序,3.6后有序了 python字段的底层实现
    40. # for i in range(1000):
    41. # conn.hset('test_hash','key_%s'%i,'鸡蛋%s号'%i)
    42. # count 是要取的条数,但是不准确,有点上下浮动
    43. # 它一般步单独用
    44. # res=conn.hscan('test_hash',cursor=0,count=19)
    45. # print(res)
    46. # print(res[0])
    47. # print(res[1])
    48. # print(len(res[1]))
    49. # res=conn.hscan('test_hash',cursor=res[0],count=19)
    50. # print(res)
    51. # print(res[0])
    52. # print(res[1])
    53. # print(len(res[1]))
    54. # 咱么用它比较多,它内部封装了hscan,做成了生成器,分批取hash类型所有数据
    55. # 14 hscan_iter(name, match=None, count=None) 获取所有hash的数据
    56. # res = conn.hscan_iter('test_hash',count=100)
    57. # print(res) # 生成器
    58. # for item in res:
    59. # print(item)
    60. conn.close()

    4.set(集合)

    Redis中的set和java中的HashSet有些类似,它内部的键值对是无序的、唯一的,他的内部实现相当于一个特殊的字典,字典中所有的value都是一个值NULL,当集合中最后一个元素被移除之后数据结构被自动删除,内存被释放

    \(\bullet\) 应用场景:

            - sinter命令可以获得A和B两个用户的共同好友

            - sismenber命令可以判断A是否是B的好友

            - scard命令可以获取好友数量

     redis是否支持事物

    redis可以说支持事务也可以说不支持,redis事务机制可以保证一致性和隔离性,但是无法保证持久性,但是对于redis而言,本身是内存数据库,所以持久性不是必须属性,原子性需要自己进行检查,尽可能保证。

    redis不像mysql一样事务的四大特性不能全部满足,但是能满足一部分,通过redis的管道实现的

    redis本身不支持事务,但是可以通过管道实现部分事务

    redis可以通过管道来保证命令要么都成功,要么都失败,完成事务的一致性,但是管道只能用在单实例,集群中不支持管道

     django中集成redis

    方式一:直接使用

    1. from user.POOL import pool
    2. import redis
    3. def index(request):
    4. conn = redis.Redis(connection_pool=pool)
    5. conn.incr('page_view')
    6. res = conn.get('page_view')
    7. return HttpResponse('被你看了%s次' % res)

    方式二:使用第三方模块

    1. # 下载第三方模块:django-redis
    2. # 配置文件中配置
    3. CACHES = {
    4. "default": {
    5. "BACKEND": "django_redis.cache.RedisCache",
    6. "LOCATION": "redis://127.0.0.1:6379/0",
    7. "OPTIONS": {
    8. "CLIENT_CLASS": "django_redis.client.DefaultClient",
    9. "CONNECTION_POOL_KWARGS": {"max_connections": 100}
    10. # "PASSWORD": "123",
    11. }
    12. }
    13. }
    14. # 使用方式
    15. from django_redis import get_redis_connection
    16. def index(request):
    17. conn = get_redis_connection(alias="default") # 每次从池中取一个链接
    18. conn.incr('page_view')
    19. res = conn.get('page_view')
    20. return HttpResponse('执行了%s次' % res)

    方式三:借助于dango的缓存使用

    1. -如果配置文件中配置了 CACHES ,以后django的缓存,数据直接放在redis中
    2. -以后直接使用cache.set 设置值,可以传过期时间
    3. -使用cache.get 获取值
    4. -强大之处在于,可以直接缓存任意的python对象,底层使用pickle实现的

  • 相关阅读:
    Blender 雕刻
    ARM 按键按下灯状态取反
    力扣-2512.奖励最顶尖的k名学生
    1496. 判断路径是否相交
    C++多线程学习02 线程的入口参数
    动态规划进阶 — — 斜率优化【3】
    【英语:语法基础】C1.日常对话-自我介绍
    ubuntu 22.04配置静态ip
    Linux命令老是记不住?一篇文章帮你解决。Linux常用命令汇总
    电脑如何截屏?一起来揭晓答案!
  • 原文地址:https://blog.csdn.net/weixin_52596593/article/details/127872774