Django笔记:Redis键值对数据库

Django笔记:Redis键值对数据库[Python常见问题]

Redis是一种nosql数据库(非关系型数据库),它的数据是以键值对的形式保存在内存中的,同时也可以定时将数据同步到磁盘文件中,即实现数据的持久化,相比于Memcached缓存系统,它支持更多的数据结构,如stringlist(队列和栈)、set(集合)、sorted set(有序集合)、hash(hash表)等。本文只是简单整理了下学习笔记,感兴趣的话可以查看中文官方文档。

一、使用场景和特点

1. 常用的使用场景

  1. 登录会话存储:存储在Redis中,与Memcached相比,数据不会丢失。
  2. 排行榜或计数器:一些实时的排行或计数都可以采用Redis来实现。
  3. 消息队列:如celery就是使用Redis作为中间人。
  4. 当前在线人数:实时的数据,但是又不需要存储到数据库中,可以采用Redis来实现。
  5. 常用的数据缓存:如论坛的首页等不会经常变化的数据存储到Redis中。
  6. 前100文章或评论进行缓存:一般情况下,用户浏览数据只会浏览前面的部分,可以把这些经常访问的数据缓存到Redis数据库中。
  7. 好友关系:微博的好友关系就是使用Redis实现的。
  8. 发布和订阅功能:可以用来做聊天软件。

2. 和Memcached的比较

比较项 Memcached Redis
类型 纯内存缓存系统 内存到磁盘同步数据库
数据类型 在定义value时就需要指定数据类型 不需要
虚拟内存 不支持 支持
过期策略 支持 支持
存储数据安全 不支持 可以将数据同步到磁盘文件中
灾难恢复 不支持 可以将磁盘中的数据恢复到内存中
分布式 支持 支持,主从同步方式
订阅与发布 不支持 支持

二、安装和使用

1. 安装与连接

Redis是不支持Windows系统的,只能在Linux上进行操作。以下示例的命令以ubuntu系统为例。
安装:sudo apt-get install redis-server
卸载:sudo apt-get purge --auto-remove redis-server
启动:安装后默认自动启动,可以通过命令查看进程信息ps aux|grep redis。也可以通过命令手动启动sudo service redis-server start(重启就是restart)。
停止:sudo service redis-server stop
连接redis-server:可以使用命令redis-cli进行连接,相当于Redis的客户端,命令格式为redis-cli -h [ip] -p [port],如redis-cli -h 127.0.0.1 -p 6379,Redis默认的启动端口为6379。
设置密码:在配置文件/etc/redis/redis.conf中放开requirepass password项,并将password替换为对应的密码即可。设置密码后还是可以正常连接,但是连接之后需要先执行auth [password]后才能进行正常的数据更新等操作,不然无法进行正常的操作。当然也可以在连接时是用-a参数指定密码,如redis-cli -h 127.0.0.1 -p 6379 -a 123456
其他机器连接本机Redis:默认只能本机连接,如果想要其他机器也能连接到本机的Redis,则需要在配置文件/etc/redis/redis.conf中给bind 127.0.0.1之后添加具体的本机ip,如bind 127.0.0.1 xxx.xxx.xxx.xxx,其他机器就能通过后面这个ip来进行连接了。

2. 常用基础操作

添加:使用setget命令进行数据的添加和获取,添加数据时默认为字符串类型,如果设置的值中含有空格则需要使用双引号包裹起来。

127.0.0.1:6379> set username zhangsan
OK
127.0.0.1:6379> get username
"zhangsan"
127.0.0.1:6379> set username "zhang san"
OK
127.0.0.1:6379> get username
"zhang san"

删除:使用del命令进行删除。

127.0.0.1:6379> del username
(nil)

设置过期时间:添加数据时如果没有设置过期时间,则默认为永久不过期。可以采用两种方式设置过期时间,一种是在添加值时进行设置:set key value EX timeoutsetex key timeout value,另一种是对已经存在的值进行设置:expire key timeouttimeout单位为秒。
查看过期时间:通过命令ttl key进行查看。
查看所有的key:通过命令keys *进行查看。
删除全部数据:flushall删除全部键值对,实际工作中慎用。

3. 常用列表操作

Redis中列表操作是有专门的命令来执行的,而不是先创建一个列表,再对列表进行操作。
在列表头/尾添加数据:lpush/rpush key value。将value插入到key对应的列表的表头/尾,如果key不存在,则创建一个空列表并执行lpush/rpush操作,如果key对应的值不是列表,则会返回一个错误。
查看列表元素:lrange key start stop。返回列表内指定区间的元素,如果要查看全部元素,则可以使用命令lrange key 0 -1
移除列表头/尾元素:lpop/rpop key。移除(弹出)列表头/尾的一个元素并返回。
移除列表多个元素:lrem key count value。删除列表中指定count个数的value元素。count大于0时,表示从表头开始搜索并删除指定个数值为value的元素;count小于0时,表示从表尾开始搜索并删除指定个数(绝对值)值为value的元素;count等于0时,表示删除全部值为value的元素。
根据索引查看列表元素:lindex key index。查看指定索引的元素。
查看列表元素个数:llen key。查看列表中的元素个数。

4. 常用集合操作

同列表一样,不需要先创建集合,再进行集合操作,在往key中添加集合数据时,如果没有则会自动创建该集合。
添加集合元素:sadd key value1 value2 ...。往集合中添加数据,可以一次添加多个值。
查看集合元素:smembers key。查看集合中的元素。
移除集合元素:srem key value1 value2。移除集合中的元素,可以一次移除多个元素。
查看集合中的元素个数:scard key。查看集合中的元素个数。
查看多个集合的交集:sinter key1 key2。查看多个集合的交集。
查看多个集合的并集:sunion key1 key2。查看多个集合的并集。
查看多个集合的差集:sdiff key1 key2。查看多个集合的差集。

5. 常用hash操作

哈希操作指的是value的数据类型为字典,同样的,不需要先创建hash表(字典)再进行操作,在添加数据时,如果hash表不存在则会自动创建。
添加数据:hset key field value。在key对应的hash表(字典)中添加一个新的键值对field/valuehmset key field1 value1 field2 value2 ...:一次添加多个键值对。
查看数据:hget key field。查看key对应的hash表(字典)中field对应的值。
删除数据:hdel key field。删除key对应的hash表(字典)中field对应的值。
查看所有的子键值对:hgetall key。查看key对应的hash表(字典)中所有的field/value
查看所有的key:hkeys/hvals key。查看key对应的hash表(字典)中所有的fieldvalue
查看是否存在某个key:hexists key field。查看key对应的hash表(字典)中是否存在指定的field
查看子键值对个数:hlen key。查看查看key对应的hash表(字典)中的键值对个数。

6. 常用事务操作

Redis事务可以一次执行多个命令,具有以下两个基本特征:

  • 隔离操作:事务中的所有命令都会序列化、按顺序执行,不会被打断。
  • 原子操作:事务中的命令要么全部执行,要么全部不执行。

开启一个事务:multi。执行这个命令后就开启了一个事务,之后的所有命令都不会被真正的执行,而是在执行该事务的时候一起执行事务中的所有命令。
执行事务:exec。执行事务中的所有命令,如果事务中的命令有报错,则该事务也会执行失败。
取消事务:discard。在使用multi命令后,执行exec命令之前,可以使用discard命令取消并退出事务。
监视:watch key1 key2 ..。监视一个或多个key,在指定监视后,在定义事务过程中,如果该key的值发生了变化,那么执行事务时,对该key的值的修改将不会生效。
取消监视:unwatch。取消监视所有的key

7. 发布订阅操作

给某个频道发布消息:publish channel messagechannel名称和message内容都可以自定义。
订阅某个频道的消息:subscribe channel1 channel2 ...。执行这个命令后,程序相当于进入了一个死循环,会一直等待发布者发布消息,一旦发布者发布了消息,那么此订阅程序就能马上收到消息。

三、持久化机制

Redis提供了两种持久化机制或者说备份方式,即RDB和AOF,它们的存储方式都是存储在磁盘的特定文件中,这两种方式的配置信息都在配置文件/etc/redis/redis.conf中,它们各自的特点可以参考如下表格。

比较项 RDB AOF
开启和关闭 默认开启。如果想要关闭,则注释掉配置文件中SNAPSHOTTING下相关save即可,如save 900 1表示如果900秒内发生了一次数据更新操作则进行一次同步,其他save也是同理,相当于每隔一定时间会检查一次,如果数据更新次数达到配置的要求则会进行同步,这也是RDB默认的同步机制。 默认关闭。如果想要开启,修改配置文件中appendonly noappendonly yes即可。
同步机制 根据配置文件中save项配置值,每隔一定时间会检查一次,如果数据更新次数达到配置的要求则会进行同步。 配置文件中提供了三种同步方式,可以根据需要打开对应的同步方式即可:appendfsync always(每发生一次更新操作则同步一次),appendfsync everysec(默认,每秒同步一次),appendfsync no(采用操作系统的更新方式,每30秒同步一次)。
存储内容 存储的是具体的键值对,如username: zhangsan,并且数据是经过压缩的。 存储的是对应的操作命令,如set username zhangsan,且数据没有经过压缩。
存储文件的路径 根据配置文件中dir(默认/var/lib/redis)和dbfilename(默认dump.rdb)两个参数来指定。 根据配置文件中dir(默认/var/lib/redis)和appendfilename(默认appendonly.aof)两个参数来指定。
优点 1)因为存储的数据经过压缩,所以文件体积比AOF小。2)因为存储的是具体的键值对,所以恢复速度比AOF块。3)适用于备份操作。 1)因为默认是每秒同步一次,所以即使发生了故障,丢失的数据也不会太多。2)因为存储的时候是在文件末尾追加命令,所以备份速度会比较快。3)如果文件过大时,AOF会对文件中的命令进行重写,只保留最小的命令集。
缺点 1)因为每次同步都会将整个文件重新压缩一次,所以一般会将同步的时间间隔设置的较长,而在这个时间内如果发生故障,则会丢失对应的数据。2)每次同步Redis都会fork出一个子进程来进同步操作,当数据量比较大的时候可能会非常耗时。 1)因为文件没有经过压缩,所以文件体积会比RDB大。2)因为每秒就会进行一次同步,所以并发量较大时,效率可能会较低。3)因为存储的是命令,所以在灾难恢复的时候会比RDB慢。

四、Python操作Redis

安装:pip install redis
Python中对应操作的方法名大多和客户端操作时的命令是一致的,可以参考命令来使用,下面只展示部分的操作方法,更多方法可以查看源码。

from redis import Redis

# 连接Redis
cache = Redis(host="192.168.1.17", port=6379, password="123456")

# 1. 普通键值对,即value为字符串类型
# 添加数据,可以使用ex参数指定过期时间
cache.set("username", "zhangsan")
# 获取数据
print(cache.get("username"))
# 删除数据
cache.delete("username")

# 2. 列表操作
# 添加数据
cache.lpush("languages", "python")
cache.lpush("languages", "java")
# 获取数据
print(cache.lrange("languages", 0, -1))

# 3. 集合操作
# 添加数据
cache.sadd("person", "zhangsan")
cache.sadd("person", "lisi")
# 获取数据
print(cache.smembers("person"))

# 4. hash操作
# 添加数据
cache.hset("person", "name", "zhangsan")
cache.hset("person", "age", "18")
# 获取数据
print(cache.hgetall("person"))

# 5. 事务操作
# 创建管道(事务)
pl = cache.pipeline()
# 添加命令
pl.set("username", "lisi")
pl.set("age", "20")
# 执行事务
pl.execute()

# 6. 发布与订阅操作
# 监听操作
ps = cache.pubsub()
# 订阅频道
ps.subscribe("mychannel")
while True:
    # 监听消息
    for message in ps.listen():
        print(message)

"""
# 发布消息(在另一个程序中运行)
from redis import Redis

# 连接Redis
cache = Redis(host="192.168.1.17", port=6379, password="123456")

# 发布消息
for i in range(5):
    cache.publish("mychannel", "xxxxx@qq.com")
"""

注:本文为学习笔记,发现错误欢迎指出。