首页 > 数据库 >redis

redis

时间:2023-11-22 23:55:30浏览次数:34  
标签:obj name res age redis print

04-01 redis

一. 简介

1. 快速了解

# 存储形式: 
    key: value对
        
# 存储位置:
    内存
        
# 支持存储的类型: 
    string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)
    
# 支持的操作: (注意: 具有原子性, 要么同时成功, 要么同时失败回滚)
    push/pop、add/remove及取交集并集和差集等   

2. 深入了解

1) 使用Redis有哪些好处?

(1) 速度快: 因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)

(2) 支持丰富数据类型: 支持string,list,set,sorted set,hash

(3) 支持事务: 操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行

(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

2) redis相比memcached有哪些优势?

(1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型

(2) redis的速度比memcached快很多

(3) redis可以持久化其数据

3) redis常见性能问题和解决方案

(1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件

(2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次

(3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内

(4) 尽量避免在压力很大的主库上增加从库

(5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...

这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。

4) MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据

相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。redis 提供 6种数据淘汰策略:

voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

no-enviction(驱逐):禁止驱逐数据

5) Memcache与Redis的区别都有哪些?

(1) 存储方式
Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。
Redis有部份存在硬盘上,这样能保证数据的持久性。

(2) 数据支持类型
Memcache对数据类型支持相对简单。
Redis有复杂的数据类型。

(3)value大小
redis最大可以达到1GB,而memcache只有1MB

6) Redis 常见的性能问题都有哪些?如何解决?

(1) Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。

(2) Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。
Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,
策略为每秒同步一次。 (3) Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。 (4) Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内

7) redis 最适合的场景

Redis最适合所有数据in-momory的场景,虽然Redis也提供持久化功能,但实际更多的是一个disk-backed的功能,跟传统意义上的持久化有比较大的差别,那么可能大家就会有疑问,似乎Redis更像一个加强版的Memcached,那么何时使用Memcached,何时使用Redis呢?

       如果简单地比较Redis与Memcached的区别,大多数都会得到以下观点:

     1 、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
     2 、Redis支持数据的备份,即master-slave模式的数据备份。
     3 、Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。

# (1) 会话缓存(Session Cache)
最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?

幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。

# (2) 全页缓存(FPC)
除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。

再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。

此外,对WordPress的用户来说,Pantheon有一个非常好的插件  wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。

# (3) 队列
Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。

如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。

# (4)排行榜/计数器
Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的
10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可: 当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行: ZRANGE user_scores 0 10 WITHSCORES Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。 # (5)发布/订阅 最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统!(不,这是真的,你可以去核实)。 Redis提供的所有特性中,我感觉这个是喜欢的人最少的一个,虽然它为用户提供如果此多功能。

3. 支持的数据类型(5大数据类型)

redis={
        k1:'123',      字符串
        k2:[1,2,3,4],   列表/数组
        k3:{1,2,3,4}     集合
        k4:{name:lqz,age:12}  字典/哈希表
        k5:{('lqz',18),('egon',33)}  有序集合
}

二. redis的安装和使用

1. linux下安装

wget http://download.redis.io/releases/redis-3.0.6.tar.gz
tar xzf redis-3.0.6.tar.gz
cd redis-3.0.6
make

启动服务端

src/redis-server

启动客户端

src/redis-cli
redis> set foo bar
OK
redis> get foo
"bar"

2. Windows下安装

详见:链接

三. Python操作Redis之安装和支持存储类型

安装redis模块

pip3 install redis

四. Python操作Redis之普通连接

介绍: redis-py提供两个类RedisStrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,

Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py

from redis import Redis

conn = Redis(host='127.0.0.1', port=6379)
conn.set('name', 'yang')
print(conn.get('name'))  # b'yang'

五. Python操作Redis之连接池

1. 链接方式一: 直接链接

import redis

pool = redis.ConnectionPool(
    host='127.0.0.1',
    port=6379,  # 提示: 本次使用host, port可以不传值. 默认已经指定
    db=1,       # 指定库. 默认会有db0~db15库
    decode_responses=True,  # 指定响应的编码是否解码. 默认不解码获取的数据是bytes类型
    max_connections=100    # 造一个池子,最多能放100个链接)
conn = redis.Redis(connection_pool=pool)
conn.set('name', 'yang')   
print(conn.get('name'))      # yang 

2. 链接方式二: 使用类方法间接链接

'''
class Redis(object):
    ...
    connection_pool = ConnectionPool.from_url(url, db=db, **kwargs)
    return cls(connection_pool=connection_pool)  # cls就是Redis类. 
 
class ConnectionPool(object):
    ...
    return cls(**kwargs)  # cls就是ConnectionPool类
'''
from redis import Redis

# 类绑定方法
conn = Redis.from_url(
    # 提示: Redis类中默认调用的ConnectionPool类中的from_url类方法.
    # scheme:[//[user:password@]host[:port]][/]path[?query-string][#anchor]
    url='redis://127.0.0.1:6379/1',   # 后面的1表示链接db1库. 下面的db=1也可以指定
    # db=1,
    decode_responses=True,
)
print(conn.get('name'))  # yang

3. 单例实现链接池

1) 定义类方法实现连接池的单例

from redis import Redis


class SingleConnectionPool(Redis):
    """使用单例模式实现连接池"""
    _POOL = None

    @classmethod
    def single(cls, url, db=None, **kwargs):
        if not cls._POOL:
            cls._POOL = cls.from_url(url, db=db, **kwargs)
        return cls._POOL


conn = SingleConnectionPool.single(
    url='redis://127.0.0.1:6379/1',
    decode_responses=True,
)
conn1 = SingleConnectionPool.single(
    url='redis://127.0.0.1:6379/1',
    decode_responses=True,
)
print(conn is conn1)      # True -> 单例

conn.set('name', 'yang')
print(conn.get('name'))   # yang

2) 使用导入模块实现连接池的单例

t_redis_pool.py

# redis连接池
import redis
# pool必须是单例的
POOL = redis.ConnectionPool(host='127.0.0.1', port=6379, max_connections=100)   # 造一个池子,最多能放100个链接.如果不指定默认是2**31次方最大

t_redis.py

from scripts.t_redis_pool import conn
from scripts.t_redis_pool import conn as conn1
print(conn is conn1)       # True -> 单例

print(conn.get('name'))    # yang

五. 操作之String操作

String操作,redis中的String在在内存中按照一个name对应一个value来存储。如图:

1. 常用方法

1) set(self, name, value, ex=None, px=None, nx=False, xx=False, keepttl=False)

'''
在Redis中设置值,默认,不存在则创建,存在则修改
参数:
    ex: 过期时间(秒)
    px: 过期时间(毫秒)
    nx: 操作不存在的值.  
        nx=True时: name这个键不存在, 当前set操作生效. 否则不生效. 
    xx: 操作存在的值
        xx=True时: name这个键存在, 当前set操作生效. 否则不生效
    keepttl: 如果为真,则保留与密钥相关的生存时间。(自redis6.0开始提供)
'''
redis_obj.set('height', 180)
redis_obj.set('height', '190', ex=2)
redis_obj.set('height', '200', px=2000)

res = redis_obj.set('height', '200', nx=True)  # 不存在操作
print(res)   # True(值不存在)  None(值存在)

res = redis_obj.set('height', '210', xx=True)  # 存在操作
print(res)     # True(值存在)  None(值不存在)

2) get(self, name)

'''
使用: 通过name键获取对应的value值
    name键存在:   返回对应name的value值
    name键不存在: 返回None
'''
res = redis_obj.get('name')
print(res)  # b'180'

res = redis_obj.get('name1')
print(res)  # None

3) mset(self, mapping)

"""
使用: 传字典类型实现批量添加数据. 
    通过字典的键设置对应redis中的键. 
    通过字典的value值设置对应redis中的value值
"""
redis_obj.mset({'name': 'yang', 'name1': 'yang1'})

4) mget(self, keys, *args)

'''
使用: 通过传多个keys键获取多个键对应的value值. 返回列表 
    传迭代器类型:   
        mget(('name', 'age', 'sex'))
        mget(['name', 'age', 'sex'])
    不传迭代器类型: 
        mget('name', 'age', 'sex')

源码分析:  内部封装了如下的方法可以支持一下的三种写法
    def list_or_args(keys, args):
        # returns a single new list combining keys and args
        try:
            # 如果传的是可迭代对象: keys=(name, name1) 则会走这里
            iter(keys)
            if isinstance(keys, (basestring, bytes)):
                keys = [keys]
            else:
                keys = list(keys)
        except TypeError:
            # 如果传的不是可迭代对象: keys=name, args=name1 则会走下面
            keys = [keys]
        if args:
            keys.extend(args)
        return keys 
'''
res = redis_obj.mget('name', 'name1')
print(res)   # [b'yang', b'yang1']

res = redis_obj.mget(('name', 'name1'))
print(res)   # [b'yang', b'yang1']

res = redis_obj.mget(['name', 'name1'])
print(res)   # [b'yang', b'yang1']

5) incr(self, name, amount=1)

'''
作用: 统计网站访问量,页面访问量,接口访问量

使用: 通过指定name键, 让其对应的value值, 增加 或 减少
    name键存在时: 在name对应的value值之前的基础之前加上amount
    name键不存在: amount作为name对应的value初始化到数据库中.

拓展: amount可以为负数
注意: name对应的value必须为整型类型, amount才能对value进行加 或者 减
'''
redis_obj.mset({'height': 180, 'width': '190'})


redis_obj.incr('height')  # 存在   height: 181
redis_obj.incr('WIDTH')   # 不存在 WIDTH: 1

redis_obj.incr('height', amount=10)  # height: 191
redis_obj.incr('width', amount=-10)  # width: 180

# 注意1: 如果不是数值类型则会抛出异常
# redis_obj.incr('name', amount=10)  # redis.exceptions.ResponseError: value is not an integer or out of range

# 注意2: 如果是浮点数的形式也会抛出异常
# redis_obj.incr('height', amount=1.1)  # redis.exceptions.ResponseError: value is not an integer or out of range

6) append(self, key, value)

'''
注意: 单个多次运行不会重复执行
使用: 通过key键在key对应的value基础之后附加新的value值
    key键存在时:  value附加到之前key对应value的末尾
    key键不存在:  value作为新的值
'''
res = redis_obj.mget('name', 'name3')
print(res)   # [b'yang', None]

res = redis_obj.append('name', 'yang')   # key存在时
print(res)   # 8 name: yangyang

res = redis_obj.append('name3', 'yang')  # key存在时
print(res)   # 4 name3: yang

7) 总结

set:  为指定键设置值
    1. ex, px: 可以控制过期事件. 秒, 毫秒
    2. nx: 可以对不存在的键操作, 对存在的键不操作. 
    3. xx: 可以对存在的键操作, 对不存在的键不操作

get:  获取指定键值. 没有返回None

mset: 传入格式字典. 字典的key对应redis中的key. 字典的value对应redis中的value

mget: 传入1个 或 多个值, 或者传入可迭代类型. 获取传入的键批量获取对应的值. 返回列表.

incr: 传入键为其值 自增 或者 自减 指定的amount. 如果键不存在就以amount作为初始化的值.

append: 为传入的键后面的附加指定的值. 提示: 单个多次运行不会重复执行

2. 不常用方法

1) getrange(self, key, start, end)

'''
使用: 通过索引起始和结束位置获取key键对应value值
'''
redis_obj.set('name', 'yang', px=200)
res = redis_obj.getrange('name', 1, 3)
print(res)  # b'ang'

2) setrange(self, name, offset, value)

'''
使用: 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加) 
    offset: 字符串的索引,字节(一个汉字三个字节)
    value: 要设置的值
'''
redis_obj.set('name', 'yang', px=200)
redis_obj.setrange('name', 1, 'A')
res = redis_obj.get('name')
print(res)  # b'yAng'

3) setex(self, name, time, value)

'''
使用: 等同于 set(self, name, value, ex=None)
    time: 传入过期时间(数字秒 或 timedelta对象
'''
redis_obj.setex('name', 3, 'yang')

4) setnx(self, name, value)

'''
使用: 等同于 set(self, name, value, nx=True)
    nx=True时: name这个键不存在, 当前set操作生效. 否则不生效.
'''
redis_obj.setnx('name', 'yang')

5) psetex(self, name, time_ms, value)

'''
使用: 等同于 set(self, name, value, px=None)
    time_ms: 传入过期时间(数字毫秒) 或 timedelta对象
'''
redis_obj.psetex('name', 3000, 'yang')

6) setbit(self, name, offset, value)

'''
使用: 对name键对应value值的二进制表示的位进行操作
    offset: 位的索引(将值变换成二进制后再进行索引)
    valu:   值只能是 1 或 0
 
如果在Redis中有一个对应: n1 = "foo",
    那么字符串foo的二进制表示为:01100110 01101111 01101111
所以,如果执行 setbit('n1', 7, 1),则就会将第7位设置为1,
    那么最终二进制则变成 01100111 01101111 01101111,即:"goo"
'''
redis_obj.setex('name', 1, 'foo')
redis_obj.setbit('name', 7, 1)
res = redis_obj.mget('name')
print(res)  # [b'goo']

7) getbit(self, name, offset)

'''
使用: 获取name对应的值的二进制表示中的某位的值 (0或1)
    如: 1的二进制是  00000001
'''
redis_obj.psetex('name', 20, 1)
res = redis_obj.getbit('name', 7)
print(res)   # 1

8) bitcount(self, key, start=None, end=None)

'''
使用: 获取name对应的值的二进制表示中 1 的个数
    key: Redis的name
    start: 位起始位置
    end: 位结束位置
'''

9) bitop(self, operation, dest, *keys)

'''
使用: 获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值

参数:
    operation,AND(并) 、 OR(或) 、 NOT(非) 、 XOR(异或)
    dest: 新的Redis的name
    *keys: 要查找的Redis的name
 
如:
    bitop("AND", 'new_name', 'n1', 'n2', 'n3')
    获取Redis中n1,n2,n3对应的值,然后讲所有的值做位运算(求并集),然后将结果保存 new_name 对应的值中
'''
redis_obj.mset({'name': 'yang', 'name1': 'yang1'})
redis_obj.bitop('AND', 'new_name', 'name1', 'name2')
res = redis_obj.getrange('new_name', 0, 10)
print(res)  # b'\x00\x00\x00\x00\x00'

10) strlen(self, name)

'''
使用: 返回name对应值的字节长度(一个汉字3个字节)
'''
redis_obj.set('name', 'yang', nx=True)
res = redis_obj.strlen('name')
print(res)  # 4

11) incrbyfloat(self, name, amount=1.0)

'''
使用: 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
参数:
    name: Redis的name
    amount: 自增数(浮点型)
'''
redis_obj.set('name', '99', xx=True)
redis_obj.incrbyfloat('name', amount=1.11)
redis_obj.incrbyfloat('xxxx', amount=1.11)
res = redis_obj.mget('name', 'xxxx')
print(res)   # [b'100.11', b'1.11']

12) decr(self, name, amount=1)

'''
使用: 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
    name: Redis的name
    amount: 自减数(整数)
'''
redis_obj.set('name', '100', px=1)
res = redis_obj.decr('name', amount=20)
print(res)  # 80

res = redis_obj.decr('name', amount=-20)
print(res)  # 100

六. 操作之Hash操作

Hash操作,redis中Hash在内存中的存储格式如下图:

1. 常用方法

1) hset(self, name, key=None, value=None, mapping=None)

'''
使用: name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
    如: python中的字典结构 dic = {'key': 'value'}
    其中redis中的name就对应着dic. key就对应的字典的key, value就对应的字典的value. 
    不同的是:redis中的name必须是唯一的. 
'''
# 1. 设置单个方式一:
redis_obj.hset('info', 'name', 'yang')

# 注意: 值不能是列表. 只支持bytes, string, int, float类型
# redis_obj.hset('info', 'hobbies', ['play', 'run'])  # Invalid input of type: 'list'. Convert to a bytes, string, int or float first.
redis_obj.hset('info', 'name', b'yang')
redis_obj.hset('info', 'sex', '男')
redis_obj.hset('info', 'height', 180)
redis_obj.hset('info', 'salaries', 10000.1)

# 2. 设置单个方式二: 不常用
redis_obj.hset('info', mapping={'weight': 125})

# 注意: 值不能有多个
# redis_obj.hset('info', mapping={'sex': '男', 'age': 18})  #  wrong number of arguments for 'hset' command

2) hget(self, name, key)

'''
使用: 在name对应的hash中获取根据key获取value
'''
res = redis_obj.hget('info', 'name')
print(res)  # b'yang'

res = redis_obj.hget('info', 'age')
print(res)  # None

3) hmset(self, name, mapping)

'''
使用:  在name对应的hash中批量设置键值对
    mapping: 字典. 如:{'k1':'v1', 'k2': 'v2'}. 
'''
redis_obj.hmset('info', {'name': b'yang', 'age': 18, 'salaries': 18.8, 'sex': "男"})

# 注意: 传入的字典value只可以传bytes, string, int, float类型
# redis_obj.hmset('info', {'name': 'yang', 'hobbies': ['play', 'run']})  # Invalid input of type: 'list'. Convert to a bytes, string, int or float first.

4) hmget(self, name, keys, *args)

'''
使用: 在name对应的hash中获取多个key的值, 返回列表格式数据.
    name: reids对应的name
    key: 要获取key集合,如:['k1', 'k2', 'k3']
    *arg: 要获取的key, 如:k1,k2,k3

提示: 内部集成了list_or_args方法. 该方法有如下作用.
    不执行可迭代类型获取name中key对应的value值 
    指定可迭代类型获取name中key对应的value值
'''
res = redis_obj.hmget('info', 'name', 'age', 'sex')
print(res)  # [b'yang', b'18', b'\xe7\x94\xb7']

res = redis_obj.hmget('info', ['name', 'age', 'sex'])
print(res)  # [b'yang', b'18', b'\xe7\x94\xb7']

res = redis_obj.hmget('info', ('name', 'age', 'sex'))
print(res)  # [b'yang', b'18', b'\xe7\x94\xb7']

# 提示: sex对应的value值是一个中文. 中文会有编码问题. 如果想要避免Redis类实例化时指定decode_responses=True参数
redis_obj = Redis(decode_responses=True)
res = redis_obj.hmget('info', 'name', 'age', 'sex')
print(res)  # ['yang', '18', '男']

5) hincrby(self, name, key, amount=1)

'''
使用: 自增name对应的hash中的指定key的值,不存在则创建key=amount
    name:   redis中的name
    key:    hash对应的key
    amount: 自增数(整数)
'''
# key存在
redis_obj.hincrby('info', 'age', amount=10)
res = redis_obj.hget('info', 'age')
print(res)  # b'28'

redis_obj.hincrby('info', 'age', amount=-10)
res = redis_obj.hmget('info', 'age')
print(res)  # [b'18']

# key不存在
redis_obj.hincrby('info', 'xxx', amount=10)
res = redis_obj.hmget('info', 'xxx')
print(res)  # [b'10']

6) hgetall(self, name)

'''
使用: 获取name对应hash的所有键值. 返回字典格式数据.
    注意: 以后想取出hash类型内所有的数据,不建议用hgetall,建议用hscan_iter
'''
res = redis_obj.hgetall('info')
print(res)  # {b'name': b'yang', ... b'xxx': b'10'}

7) hscan(self, name, cursor=0, match=None, count=None)

'''
使用: 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆
    name:   redis的name
    cursor: 游标(基于游标分批取获取数据)
    match:  匹配指定key,默认None 表示所有的key
    count:  指定每次分片最少获取个数,默认None表示获取所有.
'''
res = redis_obj.hscan('info', 0)
print(res)  # (0, {b'name': b'yang',..., b'xxx': b'10'})

res = redis_obj.hscan('info', 0, match='age')
print(res)  # (0, {b'age': b'18'})

res = redis_obj.hscan('info', count=3)
print(res)  # (0, {b'name': b'yang',..., b'xxx': b'10'})

# 注意: name不存在返回空字典
res = redis_obj.hscan('xxx')   
print(res)  # (0, {})  

8) hscan_iter(self, name, match=None, count=None)

'''
使用: 利用yield封装hscan创建生成器,实现分批去redis中获取数据
    match: 匹配指定key,默认None 表示所有的key
    count: 每次分片最少获取个数,默认None表示采用Redis的默认分片个数
'''
res = redis_obj.hscan_iter('info', count=10)
print(res)  # <generator object Redis.hscan_iter at 0x000002294395C8E0>
for item in res:
    print(item)
'''
(b'name', b'yang')
...
(b'xxx', b'10')
'''

9) 总结

hset:  通过指定hash名, 在hash名中以key, value键值对的方式存储数据. 
    注意: value值存储的范围. bytes, string, int, float.
    
hget:  通过指定hash名获取对应key下面的value值

hmset: 通过指定hash名, 传入一个字典实现批量增值. 字典的key就对应的redis中key, 字典的value就对应的redis中的value
    注意: value值存储的范围. bytes, string, int, float.

hmget: 通过指定hash名, 通过hash名可以指定多个key值, 获取每个key对应的value值. 返回列表类型.
    注意: 内部封装了list_or_args方法, 实现了如下的方式传多个key名
        hmget('info', 'name', 'age)    
        hmget('info', ('name', 'age))    
        hmget('info', ['name', 'age])
        
hincrby: 通过指定hash名, 为hash名下的key中的value进行 自增 或者 自减
    注意: 只能正对value值是整数形式            
    补充: 如果指定key不存在, 那么就会以amount初始化, 作为key的value值.
    
hscan:

hsan_inter: 内部调用hscan, 通过while循环, 批量将数据库中的数据分批次取出做成了迭代器.

2. 不常用方法

1) hlen(self, name)

'''
使用: 获取name对应的hash中键值对的个数
'''
res = redis_obj.hlen('info')
print(res)  # 7

2) hkeys(self, name)

'''
使用: 获取name对应的hash中所有的key的值
'''
res = redis_obj.hkeys('info')
print(res)  # [b'name', ..., b'age', b'xxx']

3) hvals(self, name)

'''
使用: 获取name对应的hash中所有的key的值
'''
res = redis_obj.hvals('info')
print(res)  # [b'yang', ..., b'10']

4) hexists(self, name, key)

'''
使用: 返回一个布尔值,指示“key”是否存在于散列“name”中
'''
res = redis_obj.hexists('info', 'jjj')
print(res)  # False


res = redis_obj.hexists('info', 'name')
print(res)  # True

5) hdel(self, name, keys, *args)

'''
使用: 将name对应的hash中指定key的键值对删除
'''
res = redis_obj.hmget('info', 'xxx')
print(res)  # [b'10']

res = redis_obj.hdel('info', 'xxx')
print(res)  # 1

res = redis_obj.hmget('info', 'xxx')
print(res)  # [None]

6) hincrbyfloat(self, name, key, amount=1.0)

'''
使用: 自增name对应的hash中的指定key的值,不存在则创建key=amount
    name:   redis中的name
    key:    hash对应的key
    amount: 自增数(浮点数)
 
    注意: 自增name对应的hash中的指定key的值,不存在则创建key=amount
'''
res = redis_obj.hget('info', 'salaries')
print(res)  # b'38.799999999999997'

redis_obj.hincrbyfloat('info', 'salaries', amount=10.1)
# redis_obj.hincrbyfloat('info', 'salaries', amount=-10.1)

res = redis_obj.hscan('info')[-1].get(b'salaries')
print(res)  # b'48.799999999999997'

# 注意: 指定的key不存在时. 使用amount初始化该值
redis_obj.hincrbyfloat('info', 'xxx', amount=-10.1)
res = redis_obj.hmget('info', 'xxx')
print(res)  # [b'-10.1']

七. 操作之List操作

List操作,redis中的List在在内存中按照一个name对应一个List来存储。如图:

1. 常用方法

1) lpush(self, name, *values) 和 rpush

'''
使用: 
    lpush: 将“values”推到列表“name”的顶部
    rpush: 将“values”推到列表“name”的尾部
'''
# 保存顺序: 20, 19, 18
redis_obj.lpush('age', 18, 19, 20)

# 保存顺序: 18.1, 18.2, 18.3
redis_obj.rpush('salaries', 18.1, 18.2, 18.3)

2) lpop(self, name) 和 rpop(self, name)

'''
使用: 
    lpop: 删除并返回列表name的第一项
    rpop: 删除并返回列表的最后一项“name”
'''
# lpop
redis_obj.rpush('age', 18, 19, 20)
res = redis_obj.lpop('age')
print(res)  # 18

while True:
    res = redis_obj.lpop('age')
    if not res:
        # 注意: 指定的键中的value被弹空了以后, 返回None
        print(res)  # None 
        break

# rpop
redis_obj.lpush('age', 18, 19, 20)
res = redis_obj.rpop('age')  # 18
print(res)

3) blpop(self, keys, timeout=0) 和 brpop(self, keys, timeout=0)

'''
使用: 将多个列表排列,按照从左到右弹出对应列表的元素
    keys: redis的name的集合
    timeout: 超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞

拓展:  redis_obj.brpop(keys, timeout) 从右向左弹出数据. 
    爬虫实现简单分布式:多个url放到列表里,往里不停放URL,程序循环取值,
    但是只能一台机器运行取值,可以把url放到redis中,多台机器从redis中取值,爬取数据,实现简单分布式
    
注意: 返回的是一个元组对象. 第一个值是键. 第二个值才是值
'''
# blpop
redis_obj.rpush('age', 18, 19, 20)  # 20在前
redis_obj.lpush('age', 21, 22, 23)  # 23在后  
while True:
    res = redis_obj.blpop('age', timeout=3)
    print(res)
    if not res:
        # 注意: 指定key值被弹空以后, 会按照超时时间进行等待, 在时间之内还没有新的value数据, 那么该方结束. 返回None
        print('再见!')
        break
        
# 执行结果
'''
('age', '23')
('age', '22')
('age', '21')
('age', '18')
('age', '19')
('age', '20')
None
再见!
'''


# brpop
redis_obj.rpush('age', 18, 19, 20)  # 20在前
redis_obj.lpush('age', 21, 22, 23)  # 23在后
while True:
    res = redis_obj.brpop('age', timeout=3)
    print(res)
    if not res:
        # 注意: 指定key值被弹空以后, 会按照超时时间进行等待, 在时间之内还没有新的value数据, 那么该方结束. 返回None
        print('再见!')
        break

# 执行结果
'''
('age', '20')
('age', '19')
('age', '18')
('age', '21')
('age', '22')
('age', '23')
None
再见!
'''

4) lrange(self, name, start, end)

'''
使用: 在name对应的列表分片获取数据(注意: end是闭合区间)
    name:  redis的name
    start: 索引的起始位置
    end:   索引结束位置  print(re.lrange('aa',0,re.llen('aa'))) 
'''
redis_obj.lpush('age', 18, 19, 20)
res = redis_obj.lrange('age', 0, 1)
print(res)  # ['20', '19']

5) llen(self, name)

'''
使用: name对应的list元素的个数
'''
res = redis_obj.llen('age')
print(res)

# 获取所有
res = redis_obj.lrange('age', 0, redis_obj.llen('age'))
print(res)

2. 不常用方法

1) lpushx(self, name, value) 和 rpushx(self, name, value)

'''
使用: 
    lpushx: 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
    rpushx: 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最右边
    注意: 
        1. 只能往key存在的列表中附加值
        2. 只能附加一个值.
'''
# lpushx
'''
redis_obj.lpushx('age', 18)   # 指定的键不存在时, 操作失效
res = redis_obj.lrange('age', 0, redis_obj.llen('age'))  
print(res)   # []

redis_obj.lpush('age', 18)
redis_obj.lpushx('age', 19)   # 指定的键存在时, 操作生效
res = redis_obj.lrange('age', 0, redis_obj.llen('age'))
print(res)  # ['19', '18']
'''

'''
redis_obj.rpushx('salaries', 19.1)  # 指定的键不存在时, 操作失效
res = redis_obj.lrange('salaries', 0, redis_obj.llen('salaries'))
print(res)  # []

redis_obj.rpush('salaries', 17.1, 18.1)
redis_obj.rpushx('salaries', 19.1)  # 指定的键存在时, 操作生效
res = redis_obj.lrange('salaries', 0, redis_obj.llen('salaries'))
print(res)  # ['17.1', '18.1', '19.1']

2) linsert(self, name, where, refvalue, value)

'''
使用: 更具传入的name键, 由指定where往前 还是 往后插入的顺序, 基于指定的refvalue值前 或者 后插入指定的value值
    name:     redis的name
    where:    BEFORE或AFTER(小写也可以)
    refvalue: 标杆值,即:在它前后插入数据(如果存在多个标杆值,以找到的第一个为准)
    value:    要插入的数据
    提示: 如果成功返回列表的新长度,如果refvalue不在名单中。 返回-1
'''
redis_obj.rpush('age', 18, 19, 20)
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['18', '19', '20']
# 往指定的refvalue前插入
new_len = redis_obj.linsert('age', 'before', '18', 1000)
print(redis_obj.lrange('age', 0, redis_obj.llen('age')), new_len)  # ['1000', '18', '19', '20'] 4

# 往指定的refvalue之后插入
new_len = redis_obj.linsert('age', 'after', '1000', 9999)
print(redis_obj.lrange('age', 0, redis_obj.llen('age')), new_len)  # ['1000', '9999', '18', '19', '20'] 5

# 如果refvalue不在名单中。 返回-1
res = redis_obj.linsert('age', 'before', 'xxx', 'xxxx')
print(res)  # -1

3) lset(self, name, index, value)

'''
使用: 更具传入的name键, 由值定该键中索引的位置, 将该位置的值替换成传入的value值
    name:  redis的name
    index: list的索引位置
    value: 要设置的值
'''
redis_obj.lpush('age', 19, 18)
redis_obj.lpushx('age', 17)
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['17', '18', '19']

# 对name对应的list中的某一个索引位置重新赋值 
redis_obj.lset('age', 0, 9999)

print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['9999', '18', '19']

4) lrem(self, name, count, value)

'''
使用: 更具传入的name键指定删除对应value值的个数. 从前删除个数, 还是从后删除个数, 或者全删. 由count决定
    count > 0: 删除等于从头到尾移动值的元素。
    count < 0: 删除等于从尾部移动到头部的值的元素。
    count = 0: 删除所有等于value的元素。
'''
# count > 0: 删除等于从头到尾移动值的元素。
redis_obj.rpush('age', 17, 18, 18, 19, 18)
redis_obj.rpushx('age', 19)
redis_obj.lpushx('age', 17)
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['17', '17', '18', '18', '19', '18', '19']
redis_obj.lrem('age', count=2, value=18)   # 删除操作
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['17', '17', '19', '18', '19']

# count = 0: 删除所有等于value的元素。
redis_obj.lrem('age', count=0, value=18)
redis_obj.lrem('age', count=0, value=17)
redis_obj.lrem('age', count=0, value=19)
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # []

# count < 0: 删除等于从尾部移动到头部的值的元素。
redis_obj.rpush('age', 17, 18, 18, 19, 18)
redis_obj.rpushx('age', 19)
redis_obj.lpushx('age', 17)
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['17', '17', '18', '18', '19', '18', '19']
redis_obj.lrem('age', count=-2, value=18)  # 删除操作
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['17', '17', '18', '19', '19']

5) lindex(self, name, index)

'''
使用: 在name对应的列表中根据索引获取列表元素, 负索引将返回项名单的最后一个值.
'''
redis_obj.lpush('age', 18, 19)
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['19', '18']

res = redis_obj.lindex('age', 0)
print(res)  # 19

# 负索引将返回项名单的最后一个值
res = redis_obj.lindex('age', -1)  
print(res)  # 18

6) ltrim(self, name, start, end)

'''
使用: 在name对应的列表中移除没有在start-end索引之间的值
    name:  redis的name
    start: 索引的起始位置
    end:   索引结束位置(大于列表长度,则代表不移除任何)
    提示: start和end可以和python中的切片符号一样可以是负数
'''
redis_obj.rpush('age', 18, 19, 20, 21)
redis_obj.rpop('age')
redis_obj.lpushx('age', 17)
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['17', '19', '18', '18', '19', '20']

redis_obj.ltrim('age', 0, 2)

print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['17', '18', '19']

# start和end指定负数的形式
redis_obj.ltrim('age', -2, -1)
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['18', '19']

7) rpoplpush(self, src, dst)

'''
使用: 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
    src: 要取数据的列表的name
    dst: 要添加数据的列表的name
'''
redis_obj.lpush('age', 18, 19, 19)
redis_obj.lrem('age', count=1, value=19)
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['19', '18']

redis_obj.rpoplpush('age', 'age')
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))  # ['18', '19']

8) brpoplpush(self, src, dst, timeout=0)

'''
使用: 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧
    src: 取出并要移除元素的列表对应的name
    dst: 要插入元素的列表对应的name
    timeout: 当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞
'''
# 准备数
redis_obj.rpush('age', 18, 19)

# 有数据时
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))   # ['18', '19']
redis_obj.brpoplpush('age', 'age')
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))   # ['19', '18']

# 没数据时
redis_obj.lrem('age', 0, 18)
redis_obj.lrem('age', 0, 19)
print(redis_obj.lrange('age', 0, redis_obj.llen('age')))   # []

# timeout指定超时时间
res = redis_obj.brpoplpush('age', 'age', timeout=60)
print(res)  # age不存在时等待了10秒打印了None

# 在别的文件中指定一下代码让阻塞时新增age键往其中插数据
res = redis_obj.rpush('age', 18, 19)
print(res)

3. 自定义增量迭代器

from redis import Redis

conn = Redis.from_url(
    url='redis://127.0.0.1:6379/0',
    decode_responses=True
)
# 准备数据
conn.rpush('test', *[1, 2, 3, 4, 45, 5, 6, 7, 7, 8, 43, 5, 6, 768, 89, 9, 65, 4, 23, 54, 6757, 8, 68])


def lscan_iter(name, count=10):
    index = 0

    while True:
        data_list = conn.lrange(name, index, index + count - 1)
        if not data_list:
            return
        # print(data_list, '\n-----')
        index += count
        for item in data_list:
            yield item


res = lscan_iter('test')
print(res)  # <generator object lscan_iter at 0x000001FF742B5410>
for value in res:
    print(value)

4. 总结

lpush:  对指定的name键, 新增多个value值, 每一个值都新增到列表的左边
rpush:  对指定的name键, 新增多个value值, 每一个值都新增到列表的右边
lpop:   对指定的name键中, 从左边开始查找, 弹出指定的value值. 返回结果就可以拿到弹出的value值
rpop:   对指定的name键中, 从右边开始查找, 弹出指定的value值, 返回结果就可以拿到弹出的value值.
blpop:  对指定的name键中, 从左边开始查找, 弹出指定的value值, 如果没有那么根据指定的timeout来进行等待. 如果指定为0, 表示一直等待.
brpop:  对指定的name键中, 从右边开始查找, 弹出指定的value值, 如果没有那么根据指定的timeout来进行等待. 如果指定为0, 表示一直等待.
lrange: 对指定的name键中, 根据指定的start, end进行切片(前闭后闭), 将获取到的value值, 保存到列表中作为返回值返回. 
    提示: 其中切片可以同python一样可以指定负数
llen:   获取指定的name键中的value值的个数.
    提示: 一般和lrange连用, 获取所有.
    redis_obj.lrange('name', 0, .llen('name')) 
自定义增量迭代: 
    def lscan_iter(name, count=10):
        index = 0
        while True:
            data_list = conn.lrange(name, index, index + count - 1)
            if not data_list:
                return
            
            index += count
            for item in data_list:
                yield item

八. 操作之Set操作

...

九. 其它操作

1. 准备数据

# 准备数据
redis_obj.rpush('age', 18, 19, 20)
redis_obj.hmset('info', {'name': 'yang', 'age': 18})
redis_obj.set('cache_data', 'This is zcDSB!')

2. exists(self, *names)

'''
使用: 返回存在的“名称”的数量.
'''
res = redis_obj.exists('age', 'info', 'xxxx')
print(res)  # 2

3. keys(self, pattern='*')

'''
使用: 返回与“模式”匹配的键列表
    KEYS * 匹配数据库中所有 key 。
    KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
    KEYS h*llo 匹配 hllo 和 heeeeello 等。
    KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 
'''
# 不指定默认查找所有
res = redis_obj.keys()
print(res)  # ['cache_data', 'info', 'age']

res = redis_obj.keys('*a*')
print(res)  # ['cache_data', 'age']

4. delete(self, *names)

'''
使用: 删除名称中指定的一个或多个键
    返回删除个数
'''
res = redis_obj.delete('age', 'cache_data')
print(res)   # 2

# 删除当然库中所有(慎用)
res = redis_obj.delete(*redis_obj.keys())
print(res)    # 3

5. expire(self, name, time)

'''
使用: 在键 name 上为 time 秒设置一个过期标志。
    提示: 时间可以用整数或Python时间增量对象表示。
'''
import time
import datetime
redis_obj.expire('age', datetime.timedelta(seconds=3))

time.sleep(3)

res = redis_obj.exists('age')
print(res)  # 0

6. rename(self, src, dst)

'''
使用: 将key“src”重命名为“dst”
'''
res = redis_obj.keys()
print(res)  # ['age', 'cache_data', 'info']

redis_obj.rename('age', 'AGE')

res = redis_obj.keys()
print(res)  # ['cache_data', 'info', 'AGE']

7. move(self, name, db)

'''
使用: 将键 name 移动到另一个Redis数据库 db 
'''
res = redis_obj.keys()
print(res)  # ['cache_data', 'info', 'age']

redis_obj.move('age', db=1)
res = redis_obj.keys()
print(res)  # ['cache_data', 'info']

redis_obj = Redis(db=1, decode_responses=True)
res = redis_obj.keys()
print(res)  # ['age']

8. randomkey(self)

'''
使用: 返回随机键的名称
'''
res = redis_obj.randomkey()
print(res)  # age

9. type(self, name)

'''
使用: 返回键 name '的类型
'''
for name in redis_obj.keys():
    res = redis_obj.type(name)
    print(f'{name}: res')
    
# 执行结果
'''
age: res
cache_data: res
info: res
'''

十. 利用管道开启事务

一次要么全部成功,要么失败

from redis import Redis

redis_obj = Redis(decode_responses=True)
pipe = redis_obj.pipeline(transaction=True)
pipe.multi()    # 启动事务

redis_obj.rpush('age', '18', 19)
# raise TypeError('抛出异常!')
redis_obj.rpush('age', 20)

pipe.execute()  # 提交

res = redis_obj.lrange('age', 0, redis_obj.llen('age'))
print(res)

十一. Django中使用redis(两种使用方式)

1. 通用方式

utils/redis_pool.py

from redis import Redis

conn = Redis.from_url(
    url='redis://127.0.0.1:6379/0',
    decode_responses=True
)

使用

from utils.redis_pool import conn

telephone_key = settings.PHONE_CODE_KEY % telephone

# 设置
conn.set(telephone_key, code, ex=60 * 60 * 24)    # 过期时间一天

# 获取
conn.get(telephone_key)

2. 专用方式

下载django-redis模块

pip install django-redis

配置文件中配置

# redis配置: 配置了以后django中的cache的操作方法, 就会保存到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",
        }
    }
}

使用(对象的方法重写,用法跟django的缓存一样)

from django.core.cache import cache

telephone_key = settings.PHONE_CODE_KEY % telephone

# 设置
cache.set(telephone_key, code, 60 * 10)

# 获取
cache_code = cache.get(telephone_key)

3. 使用django-redis也可以实现redis的操作

from django_redis import get_redis_connection
import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffyapi.settings.dev')

conn = get_redis_connection('default')

conn.hmset('info', {'name': 'yang', 'age': 18})
res = conn.hgetall('info')
print(res)  # {b'name': b'yang', b'age': b'18'}

十二.接口缓存

延伸:缓存雪崩、 缓存击穿、 缓存穿透

home/views.py(轮播图在数据库的数据放到redis,从redis中取)

class BannerViewSet(GenericViewSet, ListModelMixin):
    queryset = models.Banner.objects.filter(is_delete=False, is_show=True).order_by('orders')[:settings.BANNER_COUNTER]
    serializer_class = serializers.BannerModelSerializer

    def list(self, request, *args, **kwargs):
        # 把data的数据加缓存
        # 1 先去缓存拿数据
        banner_list = cache.get('banner_list')
        if not banner_list:
            # 缓存中没有,去数据库中拿
            print('走了数据库')
            response = super().list(request, *args, **kwargs)
            # 加到缓存
            cache.set('banner_list', response.data, 60*60*24)   # 过期时间是一天
            return response
        # 不用APIResponse,是重写了list方法,就用原list方法中的return
        return Response(data=banner_list)

 

标签:obj,name,res,age,redis,print
From: https://www.cnblogs.com/coderxueshan/p/17850612.html

相关文章

  • redis中查看慢日志以及返回参数值的解释
    1、问题描述 业务反馈,出现很多连接redis的readtimedout的报错  2、问题分析及解决 由于redis是单线程处理的,所有redis接收到命令,都会进入到队列中,等待执行。 当客户端,由于等待时间过长,没有接收到server端返回的数据,就是出现超时的报错。 程序里,jedis客户端,默......
  • 面试还搞不懂redis,快看看这40道面试题(下)
    21、Redis集群的主从复制模型是怎样的?答:为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品.22、Redis集群会有写操作丢失吗?为什么?答:Redis并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下......
  • redis常用知识
    1.安装aptinstallredis2.启动、停止、重启serviceredisstartserviceredisstopserviceredisrestartredis-server/etc/redis/redis.conf也可以启动kill-9进程号停止3.配置项绑定ip:如果要远程访问,将此行注释bind127.0.0.1端口:p......
  • docker 部署redis
     OKdockerrun-d--privileged=true--restart=always-p6379:6379-v/usr/local/docker/redis/6379.conf:/etc/redis/redis.conf-v/usr/local/docker/redis/data6379:/data--nameredis6379redis:7.0.5redis-server/etc/redis/redis.confdockerrun-d--privilege......
  • redis
    redis支持数据持久化,支持多种数据类型,支持数据备份性能高,数据类型丰富,支持事务,支持订阅、消息队列安装官方编译安装[root@redis:/usr/local/redis-4.0.0]#yum-yinstallgccgcc-c++[root@redis:~]#wgethttp://download.redis.io/releases/redis-4.0.0.tar.gz[root@red......
  • 10、Redis哨兵(sentinel)【面试重点】
    一、是什么二、能干嘛三、怎么玩(案例演示实战步骤)1、RedisSentinel架构,前提说明2、案例步骤2.1sentinel.conf文件位置2.2重点参数项说明2.3本次案例哨兵sentinel文件通用配置2.4先启动一主二从3个redis实例,测试正常的主从复制以下是哨兵......
  • SpringBoot使用RedisTemplate
    SpringBoot使用RedisTemplate目录1.Redis五种基础数据结构2.SpringBoot连接Redis1引入依赖2配置redis连接3编写测试类3.详解RedisTemplate的API1常用数据操作2.几种数据结构操作的具体用法1.Redis五种基础数据结构参考链接:Redis入门-数据类型:5种基础数据类......
  • Redis主从
    如何配置:方式一:6380是从,6379是主在6380上执行(去从库配置,配置主库)-在从库执行SLAVEOF127.0.0.16379,-断开关系slaveofnoone方式二:配置文件(配在从库的配置文件中)slaveof127.0.0.16379slave-read-onlyyes"""vimredis.conf #写入......
  • 手工创建Redis 集群
    官方的工具redis-trib.rb需要使用ruby,在kylin上不好安装。所以需要手工配置rediscluster。1.使用配置文件启动redis按照ip后缀拷贝到机器(90-92)上,每个机器上启动两个示例,分别使用6379和6380端口。redis启动命令:./redis-serverredis.conf启动失败处理:错误提示:1593407:M07Jul......
  • Redis集群的实例什么情况使用redis集群和哨兵
    当考虑Redis集群和哨兵的使用时,我们可以考虑一个在线购物系统的场景,其中需要处理用户会话数据。这个例子将涵盖横向扩展、高可用性和故障处理的方面。场景描述:假设你的在线购物系统使用Redis存储用户会话数据,以提供个性化的购物体验。用户的会话数据包括购物车、用户偏好设置等......