redis简单使用

Redis

  Redis是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。

  简单介绍下redis,一个高性能key-value的存储系统,支持存储的类型有string、list、set、zset和hash。在处理大规模数据读写的场景下运用比较多。

  Redis有以下特点:

    -- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。

    -- Redis支持五种数据类型。

    -- Redis支持数据库备份。
特点

  Redis的优势:

    -- Redis性能极高,读的速度是110000次/s,写的速度是81000次/s。

    -- Redis丰富的数据类型,String,Lists,Hashes,Sets以及Ordered Sets。

    -- Redis的所有操作都是原子性的,意思就是要么成功执行,要么完全失败不执行,多个操作支持事物。即MULTI和EXEC指令包起来。

    -- Redis有丰富的特性,支持publish/subscribe,通知,key过期等等特性。
优势

  Redis 配置

    -- 可以通过redis-cli 进入交互模式,使用config命令查看或设置配置项。也可以进入配置文件用vim编辑器进行修改。

# 获取所有配置项
reids 127.0.0.1:6379> config get *
# 获取单个配置项
redis 127.0.0.1:6379> config get loglevel
# 编辑配置
redis 127.0.0.1:6379> config set loglevel "notice"
配置

  Redis 数据类型

 -- String 字符串 

      -- redis的string可以包含任何数据,包括图片以及序列化的对象,一个键最大能存储512MB。

    -- Hash 哈希

      -- redis的hash是一个String类型的key和value的映射表,hash特别适合存储对象,类比python字典。

    -- List 列表

      -- redis的list是简单的字符串列表,按照插入顺序排序,可以从两端进行添加,类似于双向链表,列表还可以进行阻塞。

      -- Set 集合

      -- redis的set是字符串类型的无序且不重复集合。集合是通过哈希表实现的,所以添加,删除,查找的时间复杂度都是O(1)。

    -- Zset 有序集合

      -- redis的zset和set一样,不同的是每个元素都会关联一个double类型的分数,redis正是通过对分数的排序对集合进行有序存储。
数据类型

1.连接Redis数据库:

  -- 下载  pip install redis

  -- 连接

    Redis提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,

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

    Redis连接实例是线程安全的,可以直接将redis连接实例设置为一个全局变量,直接使用。

    如果需要另一个Redis实例(or Redis数据库)时,就需要重新创建redis连接实例来获取一个新的连接

    连接redis,加上decode_responses=True,写入的键值对中的value为str类型,不加这个参数写入的则为字节类型。

import redis
conn = redis.Redis(host="localhost", port=6379, password="", decode_responses=True)

  连接池链接

       使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。

  默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,

  然后作为参数传给Redis实例,这样就可以实现多个Redis实例共享一个连接池。

conn = redis.Redis(connection_pool=redis.ConnectionPool(
host="localhost",
port=6379,
# password="",
decode_responses=True, # 设置为str,不然可能会是bytes
db=1))
print(conn) # Redis<ConnectionPool<Connection<host=localhost,port=6379,db=1>>> 连接对象

2.String类型存取:

  set(name, value, ex=None, px=None, nx=False, xx=False)
  在Redis中设置值,默认,不存在则创建,存在则修改
    参数:
    ex,过期时间(秒)过期后值None
    px,过期时间(毫秒)
    nx,如果设置为True,则只有name不存在时,当前set操作才执行
    xx,如果设置为True,则只有name存在时,当前set操作才执行
  
  mset(self, mapping) 批量设置值
   getset(name, value) # 获取旧值,并设置新值

print(conn.set("name", "xiao_ming"))  # 返回True  写入str成功
print(conn.get('name'))  # get(self, name)  选择对应name的str

print(conn.set('name', 'bai', nx=True))  # 只有name不存在时,执行设置操作(添加),如果存在,不会修改

get_name = conn.set('name', '111', px=1000)  # 1000毫秒失效
time.sleep(1.5)
print(conn.get("name"))  # None

print(conn.set('extend', '11111', xx=True))  # None 则只有key存在时,当前set操作才执行
print(conn.get('extend'))  # None

# #  setex 设置超时str   参数为秒
print(conn.setex('token', 2, 'token_value'))  # True
time.sleep(2)
print(conn.get("token"))  # None

# 设置过期时间(豪秒)
print(conn.psetex("token", 1000, "token_value"))
time.sleep(1)
print(conn.get("token"))
View Code

3.hash类型存取:

  hset(name, key, value)  增加单个 不存在则创建

  hget(name, key)  获取单个

  hmset(name, mapping)  批量增加 mapping为字典

  hgetall(name) 获取name对应hash的所有键值

  hlen(name)  获取name对应的hash中键值对的个数

  hkeys(name)  获取name对应的hash中所有的key的值

  hvals(name)  获取name对应的hash中所有的value的值

  hexists(name, key)  检查name对应的hash是否存在当前传入的key

  hdel(name,*keys)   将name对应的hash中指定key的键值对删除

  hscan_iter(name, match=None, count=None)
    利用yield封装hscan创建生成器,实现分批去redis中获取数据
    参数:
    match,匹配指定key,默认None 表示所有的key
    count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
# hset(self, name, key, value)  # name对应的hash中设置一个键值对(不存在,则创建,否则,修改)
print(conn.hset("name", "key", "value"))  # 设置时候返回结果0 or 1  存在返回0,不存在返回1
print(conn.hset("name", "key_1", "value_1"))  # 设置时候返回结果0 or 1  存在返回0,不存在返回1
print(conn.hset("name", "key_2", "value_2"))  # 设置时候返回结果0 or 1  存在返回0,不存在返回1
print(conn.hmset("name", {"key_2": "value-2", "key_3": "value_3"}))  # True
print(conn.hget("name", "key"))  # value  单个获取
print(conn.hgetall("name"))  # {'key': 'value', 'key_1': 'value_1', 'key_2': 'value-2', 'key_3': 'value_3'} 全部获取
print(conn.hlen("name"))  # 4 获取name对应的hash中键值对的个数
print(conn.hkeys("name"))  # ['key', 'key_1', 'key_2', 'key_3']  name中全部的key
print(conn.hvals("name"))  # ['value', 'value_1', 'value-2', 'value_3']  # name中全部的value
print(conn.hdel("name", "key_3"))  # 返会 1或者0    删除name中key_3的键值对
print(conn.hexists("name", 'key_3'))  # False  检查name对应的hash是否存在当前key
print(conn.hincrby("a", "key", amount=1))  # 返回:1
print(conn.hincrby("a", "key", amount=1))  # 返回:2
print(conn.hincrby("a", "key", amount=10))  # 返回:12  #  可用于计数或者分页等
print(conn.hdel("a", "key"))
mset相关

3.list类型存取:

lpush(name,values)  # 在name对应的list中左边添加元素 可以添加多个
llen(name) # 获取name对应的列表长度
lrang(name, index1, index2) # 按照index切片取出name对应列表里值
lpushx(name, value) # 当name存在,元素左边添加
rpushx(name, value) # 当value存在,元素右边添加

linsert(name, where, refvalue, value))
  在name对应的列表的某一个值前或后插入一个新值
  参数:
  name,redis的name
  where,BEFORE或AFTER
  refvalue,标杆值,即:在它前后插入数据
  value,要插入的数据
lset(name, index, value) 给指定索引修改值

lrem(name, value, num)
  在name对应的list中删除指定的值
  参数:
  name,redis的name
  value,要删除的值
  num, num=0,删除列表中所有的指定值;
  num=2,从前到后,删除2个; num=1,从前到后,删除左边第1个
  num=-2,从后向前,删除2个

lindex(name, index) 在name对应的列表中根据索引获取列表元素

blpop(key) 没有值阻塞等待 直到有第一个值可以弹出
brpop(key) 没有值阻塞等待 直到有最后一个值可以弹出
print(conn.lpush('name', '1', '2'))  # 返回2 # 1,2 从list的左边添加,可以添加多个建
print(conn.lpush('name', *['左1', '左2']))  # 返回4 # 左1 左2  从list的左边添加,加入列表
print(conn.rpush('name', *['右1', '右2']))  # 返回6 #右1,右2  从list的右边添加,加入列表

print(conn.lpushx('no_existent', '左边加不进去'))  # 返回0  key存在左添加 不存在就添加失败
print(conn.rpushx('no_existent', '右边也加不进去'))  # 返回0  key存在右添加 不存在就添加失败

print(conn.llen('name'))  # 返回6 元素个数即list长度
print(conn.llen('no_existent'))  # 返回0 没有key相当于 len([])

print(conn.linsert("name", "BEFORE", "左1", "插入1"))  # 返回插入值所在索引  # 左1 前边  插入1
print(conn.linsert("name", "AFTER", "右1", "插入2"))  # 返回插入值所在索引   # 右1 后边插入  插入2

print(conn.lrange('name', 0, -1))  # ['左2', '插入1', '左1', '2', '1', '右1', '插入2', '右2']
print(conn.lrange("name", 1, -2))  # index切片 取出name对应列表里值 #  ['插入1', '左1', '2', '1', '右1', '插入2']

print(conn.lindex("name", -2))  # 获取该索引的值  # 插入2

print(conn.lset("name", 1, '我被修改了'))  # index为1的值修改
print(conn.lrange('name', 0, -1))  # ['左2', '我被修改了', '左1', '2', '1', '右1', '插入2', '右2']

print(conn.lrem("name", 2, "2"))  # 从前到后 删除 value为"2"的   两个  # 1 删除成功
print(conn.lrem("name", -2, "2"))  # 从后到前 删除 value为"2"的   两个  # 0 没有了  删除失败
print(conn.lrange('name', 0, -1))  # ['左2', '我被修改了', '左1', '1', '右1', '插入2', '右2']

print(conn.lpop('name'))  # 左删除一个  返回删除元素  # 左2
print(conn.rpop('name'))  # 右删除一个  返回删除元素  # 右2

print(conn.ltrim("name", 0, 2))  # 删除没在 索引内的值
print(conn.lrange("name", 1, -1))  # ['左1', '1']
list相关

3.set类型存取:

# 1. Sadd 命令将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略。
# 假如集合 key 不存在,则创建一个只包含添加的元素作成员的集合。当集合 key 不是集合类型时,返回一个错误。
print(r.sadd("1", 1))  # 输出的结果是1
print(r.sadd("1", 2))  # 输出的结果是1
print(r.sadd("1", 2))  # 因为2已经存在,不能再次田间,所以输出的结果是0
print(r.sadd("1", 3, 4))  # 输出的结果是2
print(r.sinter("1"))  # 输出的结果是set(['1', '3', '2', '4'])


# 2.Scard 命令返回集合中元素的数量。集合的数量。 当集合 key 不存在时,返回 0 。
print(r.sadd("2", 1))  # 输出的结果是1
print(r.sadd("2", 2, 3, 4, 5))  # 输出的结果是1
print(r.scard("2"))  # 输出的结果是5


# 3.Sdiff 命令返回给定集合之间的差集。不存在的集合 key 将视为空集。
print(r.sadd("31", 1, 2, 3, 4, 5, 6))  # 输出的结果是6
print(r.sadd("32", 4, 5, 6, 7, 8, 9,10))  # 输出的结果是6
print(r.sdiff(31, 32))  # 输出的结果是set(['1', '3', '2'])
print(r.sdiff(32, 31))  # 输出的结果是set(['9', '8', '7'])
print(r.sdiff(31, 31))  # 输出的结果是set([])

#
4.Sdiffstore 命令将给定集合之间的差集存储在指定的集合中。如果指定的集合 key 已存在,则会被覆盖。 print(r.sadd("41", 1, 2, 3, 4, 5, 6)) # 输出的结果是6 print(r.sadd("42", 4, 5, 6, 7, 8, 9)) # 输出的结果是6 print(r.sadd("43", 0)) # 输出的结果是1 print(r.sdiffstore("43", "41", "42")) # 输出的结果是3 print(r.sinter("43")) # 输出的结果是 set(['1', '3', '2'])

#
5.Sinter 命令返回给定所有给定集合的交集。 不存在的集合 key 被视为空集。 当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。 print(r.sadd("51", 3, 4, 5, 6)) # 输出的结果是4 print(r.sadd("52", 1, 2, 3, 4)) # 输出的结果是4 print(r.sinter(51, 52)) # 输出的结果是set(['3', '4']) print(r.sadd("53", 1, 2, 3, 4, 5, 6)) # 输出的结果是6 print(r.sadd("54", 3, 4, 5, 6, 7, 8, 9)) # 输出的结果是7 print(r.sinter(53, 54)) # 输出的结果是set(['3', '5', '4', '6']) print(r.sinter(53, 56)) # 输出的结果是set([])
#
6.Sinterstore 命令将给定集合之间的交集存储在指定的集合中。如果指定的集合已经存在,则将其覆盖。 print(r.sadd("61", 3, 4, 5, 6)) # 输出的结果是4 print(r.sadd("62", 1, 2, 3, 4)) # 输出的结果是4 print(r.sadd("63", 0)) # 输出的结果是1 print(r.sinterstore(63, 61, 62)) # 输出的结果是2 print(r.sinter(63)) # 输出的结果是set(['3', '4'])

#
7.Sismember 命令判断成员元素是否是集合的成员。 # 如果成员元素是集合的成员,返回 1 。 如果成员元素不是集合的成员,或 key 不存在,返回 0 。 print(r.sadd("71", 1, 2, 3, 4, 5, 6)) # 输出的结果是6 print(r.sismember("71", 1)) # 输出的结果是True print(r.sismember("71", 2)) # 输出的结果是True print(r.sismember("71", 7)) # 输出的结果是False print(r.sismember("71", 8)) # 输出的结果是False

#
8.Smembers 命令返回集合中的所有的成员。 不存在的集合 key 被视为空集合。 print(r.sadd("81", 1, 2, 3, 4, 5, 6)) # 输出的结果是6 print(r.smembers(81)) # 输出的结果是set(['1', '3', '2', '5', '4', '6']) print(r.smembers(82)) # 输出的结果是set([])

#
9.Smove 命令将指定成员 member 元素从 source 集合移动到 destination 集合。 # SMOVE 是原子性操作。 # 如果 source 集合不存在或不包含指定的 member 元素,则 SMOVE 命令不执行任何操作,仅返回 False 。否则, member 元素从 source 集合中被移除,并添加到 destination 集合中去。 # 当 destination 集合已经包含 member 元素时, SMOVE 命令只是简单地将 source 集合中的 member 元素删除。 # 当 source 或 destination 不是集合类型时,返回一个错误。 # 如果成员元素被成功移除,返回 True。 如果成员元素不是 source 集合的成员,并且没有任何操作对 destination 集合执行,那么返回 False print(r.sadd("91", 1, 2, )) # 输出的结果是2 print(r.sadd("92", 3, 4, )) # 输出的结果是2 print(r.smove(91, 92, 1)) # 把91中的1移动到92中去,输出的结果是True print(r.smembers("91")) # 输出的结果是set(['2']) print(r.smembers("92")) # 输出的结果是set(['1', '3', '4']) print(r.smove(91, 92, 5)) # 91不存在5,输出的结果是False print(r.smembers("91")) # 输出的结果是set(['2']) print(r.smembers("92")) # 输出的结果是set(['1', '3', '4']) # 10. Spop 命令用于移除并返回集合中的一个随机元素。 print(r.sadd("10", 1, 2, 3, 4, 5, 6)) # 输出的结果是6 print(r.spop("10")) # 输出的结果是3 print(r.smembers("10")) # 输出的结果是set(['1', '2', '5', '4', '6']) print(r.spop("10")) # 输出的结果是1 print(r.smembers("10")) # 输出的结果是set(['2', '5', '4', '6'])

#
11.Srandmember 命令用于返回集合中的一个随机元素。 # 从 Redis 2.6 版本开始, Srandmember 命令接受可选的 count 参数: # 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合。 # 如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。 # 该操作和 SPOP 相似,但 SPOP 将随机元素从集合中移除并返回,而 Srandmember 则仅仅返回随机元素,而不对集合进行任何改动。 print(r.sadd("11", 1, 2, 3, 4, 5, 6)) # 输出的结果是6 print(r.srandmember(11)) # 输出的结果是4 print(r.smembers(11)) # 输出的结果是set(['1', '3', '2', '5', '4', '6']) print(r.srandmember(11, 3)) # 输出的结果是['6', '3', '1'] print(r.smembers(11)) # 输出的结果是set(['1', '3', '2', '5', '4', '6'])

#
12. Srem 命令用于移除集合中的一个或多个成员元素,不存在的成员元素会被忽略。 # 当 key 不是集合类型,返回一个错误。 # 被成功移除的元素的数量,不包括被忽略的元素。 print(r.sadd("12", 1, 2, 3, 4, 5, 6, 7)) # 输出的结果是7 print(r.srem("12", 1)) # 输出的结果是1 print(r.smembers("12")) # 输出的结果是set(['3', '2', '5', '4', '7', '6']) print(r.srem("12", 8)) # 输出的结果是0 print(r.smembers("12")) # 输出的结果是set(['3', '2', '5', '4', '7', '6'])

#
13.Sunion 命令返回给定集合的并集。不存在的集合 key 被视为空集。 print(r.sadd("131", 1, 2, 3, 4, 5, 6, 7)) # 输出的结果是7 print(r.sadd("132", 0, 1, 2, 7, 8, 9)) # 输出的结果是6 print(r.sunion(131, 132)) # 输出的结果是set(['1', '0', '3', '2', '5', '4', '7', '6', '9', '8']) print(r.sunion(131, 134)) # 输出的结果是set(['1', '3', '2', '5', '4', '7', '6'])

#
14.Sunionstore 命令将给定集合的并集存储在指定的集合 destination 中。 print(r.sadd("141", 1, 2, 3, 4, 5, 6, 7)) # 输出的结果是7 print(r.sadd("142", 0, 1, 2, 3, 4)) # 输出的结果是5 print(r.sunionstore(143, 141, 142)) # 输出的结果是8 print(r.smembers(143)) # 输出的结果是set(['1', '0', '3', '2', '5', '4', '7', '6'])

#
15.Sscan 命令用于迭代集合键中的元素。 print(r.sadd("151", 1, 2, 3, 4, 5, 6, 7)) # 输出的结果是7 print(r.sscan(151, cursor=2, match=1, count=1)) # 输出的结果是 (0L, ['1'])

有序集合的命令 请移步官方文档~~~~

4.pipeline管道批量处理

Pipeline指的是管道技术,指的是客户端允许将多个请求依次发给服务器,过程中而不需要等待请求的回复,在最后再一并读取结果即可。
管道技术使用广泛,例如许多POP3协议已经实现支持这个功能,大大加快了从服务器下载新邮件的过程。
Redis很早就支持管道(pipeline)技术。(因此无论你运行的是什么版本,你都可以使用管道(pipelining)操作Redis)

import redis

# 连接池链接
r = redis.Redis(connection_pool=redis.ConnectionPool(
    host="localhost",
    port=6379,
    # password="",
    decode_responses=True,  # 设置为str,不然可能会是bytes
    db=4))

li = [
    {"id": "111", "class": 1, "on_line": "1"},
    {"id": "111", "class": 2, "on_line": "0"},
    {"id": "222", "class": 1, "on_line": "0"},
]

# 操作量大的情况   有点慢
# for i in li:
#     r.hset(i.get('id'), i.get('class'), i.get("on_line"))

pipe = r.pipeline()  # 管道批量操作  # 大量节省io调高效率
[pipe.hset(i.get('id'), i.get('class'), i.get("on_line")) for i in li]  # 要执行的命令, 放在管道但没执行
pipe.execute()  # 执行所有的命令
[pipe.hget(i.get('id'), i.get('class')) for i in li]
print([li[i] for i, x in enumerate(pipe.execute()) if x == "1"])  # 筛选出结果为'1'的序号

pipeline 可以链式操作

pipe.set('hello', 'redis').sadd('faz', 'baz').incr('num').execute()
print(r.get("num"))  # incr统计次数使用

 

5.delete使用

py-redis中有个delete接口,既可以删除单个key,也可以批量删除key,后者的正确用法网上很少,我在实践中遇到该问题,特此记录一下。

删除单个key

r.delete('age')
r.delete('sex', 'age')

删除所有的key

keys = r.keys()
r.delete(*keys)  # 执行成功,返回删除key的个数,否则返回0

 

5.过期使用

pipe.expire()

 

posted @ 2019-11-04 17:38  洛丶丶丶  阅读(230)  评论(0编辑  收藏  举报