目录
redis 是一个 Key-Value 数据库,Value 支持 string(字符串),list(列表),set(集合),zset(有序集合),hash(哈希类型)等类型。
一、安装
pip install redis
二、连接redis两种方式
1、方式1常规连接redis
import redis
r = redis(host='localhost', port=6379, db=0)
r.set('foo', 'bar')
print(r.get('foo'))
输出结果为:
b'bar'
2、方式2使用连接池
默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数 Redis,这样就可以实现多个 Redis 实例共享一个连接池。
import redis
pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
r = redis.Redis(connection_pool=pool)
r.set('foo', 'bar')
print(r.get('foo'))
r.close()# 记得关闭连接池
输出结果为:
b'bar'
三、输出结果修改
redis 取出的结果默认是字节,我们可以设定 decode_responses=True 改成字符串
import redis
r = redis(host='localhost', port=6379, db=0, decode_responses=True)
r.set('foo', 'bar')
print(r.get('foo'))
输出结果为:
'bar'
四、redis六种数据类型
1、redis不同数据类型使用场景
1)String
计数器应用
2)List
取最新N个数据的操作
消息队列
删除与过滤
实时分析正在发生的情况,用于数据统计与防止垃圾邮件(结合Set)
3)Set
Uniqe操作,获取某段时间所有数据排重值
实时系统,反垃圾系统
共同好友、二度好友
利用唯一性,可以统计访问网站的所有独立IP
好友推荐的时候,根据tag求交集,大于某个threshold就可以推荐
4)Hash
存储、读取、修改用户属性
5)Sorted Set
排行榜应用,取TOP N操作
需要精准设定过期时间的应用(时间戳作为Score)
带有权重的元素,比如一个游戏的用户得分排行榜
过期项目处理,按照时间排序
2、redis六种不同数据类型实例
1)字符串类型String
-
redis中的String在在内存中按照一个name对应一个value来存储。如图:
1.1 set 添加字符串
set(name, value, ex=None, px=None, nx=False, xx=False)
在 Redis 中设置值,默认,不存在则创建,存在则修改。
参数:
-
ex - 过期时间(秒)
-
px - 过期时间(毫秒)
-
nx - 如果设置为True,则只有name不存在时,当前set操作才执行(新建)
# 前提redis数据库db 当中没有key='foo' import redis r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True) r.set('foo', 'bar', nx=True) print(r.get('foo'))
输出:
'bar'
-
xx - 如果设置为True,则只有name存在时,当前set操作才执行(修改)
# 前提redis数据库db=3 当中没有key='foo'
import redis
r = redis.Redis(host='199.28.10.122', port=6389, db=3, password='test1234', decode_responses=True)
r.set('foo', 'bar', xx=True)
print(r.get('foo'))
输出:
None
1.2 setnx KEY值不存在时,添加
setnx(name, value)
设置值,只有name不存在时,执行设置操作(添加)
# 前提redis数据库db当中没有key='too'
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
r.setnx('too', 'tar')
print(r.get('too'))
r.setnx('too', 'looktar')
print(r.get('too'))
输出:
‘tar’
‘tar’ # 因为第一个setnx已经添加了对应数据,所以执行setnx添加('too', 'looktar')是不执行的
1.3 setex 设置过期时间秒
setex(name, time, value)
设置值
参数:
time - 过期时间(数字秒 或 timedelta对象)
import redis
import time
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
r.setex('foo', 5, 'bar')
print(r.get('foo'))
print('等待5秒')
time.sleep(5)
print(r.get('foo'))
运行结果:
bar
等待5秒
None # 5秒之后数据过期了
1.4 psetex 设置过期时间毫秒
psetex(name, time_ms, value)
设置值
参数:
time_ms - 过期时间(数字毫秒 或 timedelta对象)
import redis
import time
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
r.psetex('foo', 5000, 'bar')
print(r.get('foo'))
print('等待5秒')
time.sleep(5)
print(r.get('foo'))
运行结果:
bar
等待5秒
None # 5秒之后数据过期了
1.5 mset 批量设置
mset(mapping)
批量设置值
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
r.mset({'k1': 'v1', 'k2': 'v2'})
print(r.mget("k1", "k2")) # 一次取出多个键对应的值
print(r.mget("k1"))
运行结果:
['v1', 'v2']
['v1']
1.6 mget 批量获取
mget(keys, *args)
批量设置值
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
r.mset({'k1': 'v1', 'k2': 'v2'})
print(r.mget("k1", "k2")) # 一次取出多个键对应的值
# 或
print(r.mget(["k1", "k2"])) # 一次取出多个键对应的值
print(r.mget("k1"))
运行结果:
['v1', 'v2']
['v1', 'v2']
['v1']
1.7 getset设置新值并获取原来的值
getset(name, value)
设置并获取原来的值
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
r.set('food', 'beef')
print(r.get('food'))
print(r.getset("food", "barbecue")) # 设置的新值是barbecue 设置前的值是beef
print(r.get('food'))
运行结果:
beef # 原来的值
beef # return的是原来的值
barbecue # 重新获取“food”的值
1.8 getrange获取子序列(根据字节获取,非字符)
getrange(key, start, end)
获取子序列(根据字节获取,非字符)
参数:
-
name - Redis 的 name
-
start - 起始位置(字节)
-
end - 结束位置(字节)
如: "祖国万岁" ,0-3表示 "祖"(Python中字符汉字在utf-8编码下占三个字节,在gbk编码下占两个字节)
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
r.set("cn_name", "祖国万岁") # 汉字
print(r.getrange("cn_name", 0, 2)) # 取索引号是0-2 前3位的字节 祖 切片操作 (一个汉字3个字节 1个字母一个字节 每个字节8bit)
print(r.getrange("cn_name", 0, -1)) # 取所有的字节 祖国万岁 切片操作
r.set("en_name","zuguowansui") # 字母
print(r.getrange("en_name", 0, 2)) # 取索引号是0-2 前3位的字节 zug 切片操作 (一个汉字3个字节 1个字母一个字节 每个字节8bit)
print(r.getrange("en_name", 0, -1)) # 取所有的字节 uguowansui 切片操作
运行结果:
祖
祖国万岁
zug
zuguowansui
1.9 setrange修改字符串内容
setrange(name, offset, value)
修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
参数:
-
offset - 字符串的索引,字节(一个汉字三个字节)
-
value - 要设置的值
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
r.setrange("en_name", 1, "ccc")
print(r.get("en_name")) # zcccowansui 原始值是zuguowansui 从索引号是1开始替换成ccc
运行结果:
zcccowansui
1.10 setbit对 name 对应值的二进制表示的位进行操作
setbit(name, offset, value)
-
对 name 对应值的二进制表示的位进行操作
参数:
-
name - redis的name
-
offset - 位的索引(将值变换成二进制后再进行索引)
-
value - 值只能是 1 或 0
注:如果在Redis中有一个对应: n1 = "foo",
那么字符串foo的二进制表示为:01100110 01101111 01101111
所以,如果执行 setbit('n1', 7, 1),则就会将第7位设置为1,
那么最终二进制则变成 01100111 01101111 01101111,即:"goo"
-
1.11 getbit 获取name对应的值的二进制表示中的某位的值 (0或1)
getbit(name, offset)
获取name对应的值的二进制表示中的某位的值 (0或1)
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
print(r.getbit("foo1", 0)) # 0 foo1 对应的二进制 4个字节 32位 第0位是0还是1
1.12 bitcount获取name对应的值的二进制表示中 1 的个数
bitcount(key, start=None, end=None)
获取name对应的值的二进制表示中 1 的个数
参数:
-
key - Redis的name
-
start - 字节起始位置
-
end - 字节结束位置
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
r.set('foo','baksks')
print(r.get("foo")) # goo1 01100111
print(r.bitcount("foo",0,1)) # 11
运行结果:
baksks
6
1.13 bittop获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值
bitop(operation, dest, *keys)
获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值
参数:
-
operation - AND(并) 、 OR(或) 、 NOT(非) 、 XOR(异或)
-
dest - 新的Redis的name
-
*keys - 要查找的Redis的name
如:
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
r.set("n1", 'goo1')
r.set("n2", 'baaanew')
r.set("n3", 'appaanew')
r.bitop("AND", 'new_name', 'n1', 'n2', 'n3')
print(r.get('new_name'))
运行结果:
```!
1.14 strlen返回name对应值的字节长度(一个汉字3个字节)
strlen(name)
返回name对应值的字节长度(一个汉字3个字节)
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
r.set('foo1s', 'flash')
print(r.strlen("foo1s"))
运行结果:
5
1.15 incr自增 name 对应的值,当 name 不存在时,则创建 name=amount,否则,则自增
incr(self, name, amount=1)
自增 name 对应的值,当 name 不存在时,则创建 name=amount,否则,则自增。
参数:
-
name - Redis的name
-
amount - 自增数(必须是整数)
注:同 incrby
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
r.set('foo1', 'flash')
r.set('foo2', 'fla2sh')
r.set("foo", 123)
print(r.mget("foo", "foo1", "foo2", "k1", "k2"))
r.incr("foo", amount=1)
print(r.mget("foo", "foo1", "foo2", "k1", "k2"))
r.incr("foono", amount=1) # 不存在‘foono’
print(r.mget("foono", "foo1", "foo2", "k1", "k2"))
运行结果:
['123', 'flash', 'fla2sh', 'v1', 'v2']
['124', 'flash', 'fla2sh', 'v1', 'v2']
['1', 'flash', 'fla2sh', 'v1', 'v2'] # 当 name 不存在时,则创建 name=amount
应用场景:
假定我们对一系列页面需要记录点击次数。例如论坛的每个帖子都要记录点击次数,而点击次数比回帖的次数的多得多。如果使用关系数据库来存储点击,可能存在大量的行级锁争用。所以,点击数的增加使用redis的INCR命令最好不过了。
当redis服务器启动时,可以从关系数据库读入点击数的初始值