Django笔记:Redis键值对数据库
Redis是一种nosql
数据库(非关系型数据库),它的数据是以键值对的形式保存在内存中的,同时也可以定时将数据同步到磁盘文件中,即实现数据的持久化,相比于Memcached缓存系统,它支持更多的数据结构,如string
、list
(队列和栈)、set
(集合)、sorted set
(有序集合)、hash
(hash表)等。本文只是简单整理了下学习笔记,感兴趣的话可以查看中文官方文档。
一、使用场景和特点
1. 常用的使用场景
- 登录会话存储:存储在Redis中,与Memcached相比,数据不会丢失。
- 排行榜或计数器:一些实时的排行或计数都可以采用Redis来实现。
- 消息队列:如celery就是使用Redis作为中间人。
- 当前在线人数:实时的数据,但是又不需要存储到数据库中,可以采用Redis来实现。
- 常用的数据缓存:如论坛的首页等不会经常变化的数据存储到Redis中。
- 前100文章或评论进行缓存:一般情况下,用户浏览数据只会浏览前面的部分,可以把这些经常访问的数据缓存到Redis数据库中。
- 好友关系:微博的好友关系就是使用Redis实现的。
- 发布和订阅功能:可以用来做聊天软件。
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. 常用基础操作
添加:使用set
和get
命令进行数据的添加和获取,添加数据时默认为字符串类型,如果设置的值中含有空格则需要使用双引号包裹起来。
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 timeout
或setex key timeout value
,另一种是对已经存在的值进行设置:expire key timeout
。timeout
单位为秒。
查看过期时间:通过命令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/value
。hmset 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表(字典)中所有的field
或value
。
查看是否存在某个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 message
。channel
名称和message
内容都可以自定义。
订阅某个频道的消息:subscribe channel1 channel2 ...
。执行这个命令后,程序相当于进入了一个死循环,会一直等待发布者发布消息,一旦发布者发布了消息,那么此订阅程序就能马上收到消息。
三、持久化机制
Redis提供了两种持久化机制或者说备份方式,即RDB和AOF,它们的存储方式都是存储在磁盘的特定文件中,这两种方式的配置信息都在配置文件/etc/redis/redis.conf
中,它们各自的特点可以参考如下表格。
比较项 | RDB | AOF |
---|---|---|
开启和关闭 | 默认开启。如果想要关闭,则注释掉配置文件中SNAPSHOTTING 下相关save 即可,如save 900 1 表示如果900秒内发生了一次数据更新操作则进行一次同步,其他save 也是同理,相当于每隔一定时间会检查一次,如果数据更新次数达到配置的要求则会进行同步,这也是RDB默认的同步机制。 |
默认关闭。如果想要开启,修改配置文件中appendonly no 为appendonly 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")
"""
注:本文为学习笔记,发现错误欢迎指出。