redis 提供两个类 Redis 和 StrictRedis 用于实现 Redis 的命令,StrictRedis 用于实现大部分官方的命令,并使用官方的语法和命令,Redis 是 StrictRedis 的子类,用于向后兼容旧版本的 redis-py。
redis 连接实例是线程安全的,可以直接将 redis 连接实例设置为一个全局变量,直接使用。如果需要另一个 Redis 实例(or Redis 数据库)时,就需要重新创建 redis 连接实例来获取一个新的连接。同理,python 的 redis 没有实现 select 命令。
安装 redis
pip install redis
连接 redis,加上 decode_responses=True,写入的键值对中的 value 为 str 类型,不加这个参数写入的则为字节类型。
- import redis # 导入redis模块,通过python操作redis 也可以直接在redis主机的服务端操作缓存数据库
- r = redis.Redis(host='localhost', port=6379, decode_responses=True) # host是redis主机,需要redis服务端和客户端都启动 redis默认端口是6379
- r.set('name', 'junxi') # key是"foo" value是"bar" 将键值对存入redis缓存
- print(r['name'])
- print(r.get('name')) # 取出键name对应的值
- print(type(r.get('name')))
redis-py 使用 connection pool 来管理对一个 redis server 的所有连接,避免每次建立、释放连接的开销。默认,每个 Redis 实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数 Redis,这样就可以实现多个 Redis 实例共享一个连接池
连接池
- import redis # 导入redis模块,通过python操作redis 也可以直接在redis主机的服务端操作缓存数据库
- pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True) # host是redis主机,需要redis服务端和客户端都起着 redis默认端口是6379
- r = redis.Redis(connection_pool=pool)
- r.set('gender', 'male') # key是"gender" value是"male" 将键值对存入redis缓存
- print(r.get('gender')) # gender 取出键male对应的值
set(name, value, ex=None, px=None, nx=False, xx=False)
在 Redis 中设置值,默认,不存在则创建,存在则修改参数:ex,过期时间(秒)px,过期时间(毫秒)nx,如果设置为 True,则只有 name 不存在时,当前 set 操作才执行 xx,如果设置为 True,则只有 name 存在时,当前 set 操作才执行
1.ex,过期时间(秒) 这里过期时间是 3 秒,3 秒后 p,键 food 的值就变成 None
- import redis
- pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
- r = redis.Redis(connection_pool=pool)
- r.set('food', 'mutton', ex=3) # key是"food" value是"mutton" 将键值对存入redis缓存
- print(r.get('food')) # mutton 取出键food对应的值
2.px,过期时间(豪秒) 这里过期时间是 3 豪秒,3 毫秒后,键 foo 的值就变成 None
- import redis
- pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
- r = redis.Redis(connection_pool=pool)
- r.set('food', 'beef', px=3)
- print(r.get('food'))
3.nx,如果设置为 True,则只有 name 不存在时,当前 set 操作才执行 (新建)
- import redis
- pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
- r = redis.Redis(connection_pool=pool)
- print(r.set('fruit', 'watermelon', nx=True)) # True--不存在
- # 如果键fruit不存在,那么输出是True;如果键fruit已经存在,输出是None
4.xx,如果设置为 True,则只有 name 存在时,当前 set 操作才执行 (修改)
- print((r.set('fruit', 'watermelon', xx=True))) # True--已经存在
- # 如果键fruit已经存在,那么输出是True;如果键fruit不存在,输出是None
5.setnx(name, value) 设置值,只有 name 不存在时,执行设置操作(添加)
- print(r.setnx('fruit1', 'banana'))#fruit1不存在,输出为True
6.setex(name, value, time) 设置值参数:time,过期时间(数字秒 或 timedelta 对象)
- import redis
- import time
- pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
- r = redis.Redis(connection_pool=pool)
- r.setex("fruit2", "orange", 5)
- time.sleep(5)
- print(r.get('fruit2')) # 5秒后,取值就从orange变成None
7.psetex(name, time_ms, value) 设置值参数:time_ms,过期时间(数字毫秒 或 timedelta 对象)
- r.psetex("fruit3", 5000, "apple")
- time.sleep(5)
- print(r.get('fruit3')) # 5000毫秒后,取值就从apple变成None
8.mset(*args, **kwargs) 批量设置值如:
- r.mget({
- 'k1': 'v1',
- 'k2': 'v2'
- }) r.mset(k1 = "v1", k2 = "v2")#这里k1和k2不能带引号一次设置对个键值对print(r.mget("k1", "k2"))#一次取出多个键对应的值print(r.mget("k1"))
9.mget(keys, *args) 批量获取如:
- print(r.mget('k1', 'k2'))
- print(r.mget(['k1', 'k2']))
- print(r.mget("fruit", "fruit1", "fruit2", "k1", "k2")) # 将目前redis缓存中的键对应的值批量取出来
10.getset(name, value) 设置新值并获取原来的值
- print(r.getset("food", "barbecue"))#设置的新值是barbecue设置前的值是beef
11.getrange(key, start, end) 获取子序列(根据字节获取,非字符)参数:name,Redis 的 namestart,起始位置(字节)end,结束位置(字节)如: "君惜大大" ,0-3 表示 "君"
- 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","junxi") # 字母
- print(r.getrange("en_name", 0, 2)) # 取索引号是0-2 前3位的字节 jun 切片操作 (一个汉字3个字节 1个字母一个字节 每个字节8bit)
- print(r.getrange("en_name", 0, -1)) # 取所有的字节 junxi 切片操作
12.setrange(name, offset, value) 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)参数:offset,字符串的索引,字节(一个汉字三个字节)value,要设置的值
- r.setrange("en_name", 1, "ccc")
- print(r.get("en_name")) # jccci 原始值是junxi 从索引号是1开始替换成ccc 变成 jccci
13.setbit(name, offset, value) 对 name 对应值的二进制表示的位进行操作参数:name,redis 的 nameoffset,位的索引(将值变换成二进制后再进行索引)value,值只能是 1 或 0
- 注:如果在Redis中有一个对应: n1 = "foo",
- 那么字符串foo的二进制表示为:01100110 01101111 01101111
- 所以,如果执行 setbit('n1', 7, 1),则就会将第7位设置为1,
- 那么最终二进制则变成 01100111 01101111 01101111,即:"goo"
- 扩展,转换二进制表示:
- source = "陈思维"
- source = "foo"
- for i in source:
- num = ord(i)
- print bin(num).replace('b','')
- 特别的,如果source是汉字 "陈思维"怎么办?
- 答:对于utf-8,每一个汉字占 3 个字节,那么 "陈思维" 则有 9个字节
- 对于汉字,for循环时候会按照 字节 迭代,那么在迭代时,将每一个字节转换 十进制数,然后再将十进制数转换成二进制
- 11100110 10101101 10100110 11100110 10110010 10011011 11101001 10111101 10010000
14.getbit(name, offset) 获取 name 对应的值的二进制表示中的某位的值 (0 或 1)
- print(r.getbit("foo1", 0))#0 foo1对应的二进制4个字节32位第0位是0还是1
15.bitcount(key, start=None, end=None) 获取 name 对应的值的二进制表示中 1 的个数参数:key,Redis 的 namestart 字节起始位置 end,字节结束位置
- print(r.get("foo")) # goo1 01100111
- print(r.bitcount("foo",0,1)) # 11 表示前2个字节中,1出现的个数
16.bitop(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 对应的值中
- r.set("foo","1") # 0110001
- r.set("foo1","2") # 0110010
- print(r.mget("foo","foo1")) # ['goo1', 'baaanew']
- print(r.bitop("AND","new","foo","foo1")) # "new" 0 0110000
- print(r.mget("foo","foo1","new"))
- source = "12"
- for i in source:
- num = ord(i)
- print(num) # 打印每个字母字符或者汉字字符对应的ascii码值 f-102-0b100111-01100111
- print(bin(num)) # 打印每个10进制ascii码值转换成二进制的值 0b1100110(0b表示二进制)
- print bin(num).replace('b','') # 将二进制0b1100110替换成01100110
17.strlen(name) 返回 name 对应值的字节长度(一个汉字 3 个字节)
- print(r.strlen("foo"))#4 'goo1'的长度是4
18.incr(self, name, amount=1) 自增 name 对应的值,当 name 不存在时,则创建 name=amount,否则,则自增。参数:name,Redis 的 nameamount, 自增数(必须是整数)注:同 incrby
- 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"))
应用场景 – 页面点击数假定我们对一系列页面需要记录点击次数。例如论坛的每个帖子都要记录点击次数,而点击次数比回帖的次数的多得多。如果使用关系数据库来存储点击,可能存在大量的行级锁争用。所以,点击数的增加使用 redis 的 INCR 命令最好不过了。当 redis 服务器启动时,可以从关系数据库读入点击数的初始值(12306 这个页面被访问了 34634 次)
- r.set("visit:12306:totals", 34634)
- print(r.get("visit:12306:totals"))
每当有一个页面点击,则使用 INCR 增加点击数即可。
- r.incr("visit:12306:totals")
- r.incr("visit:12306:totals")
页面载入的时候���可直接获取这个值
- print(r.get("visit:12306:totals"))
19.incrbyfloat(self, name, amount=1.0) 自增 name 对应的值,当 name 不存在时,则创建 name=amount,否则,则自增。参数:name,Redis 的 nameamount, 自增数(浮点型)
- r.set("foo1", "123.0")
- r.set("foo2", "221.0")
- print(r.mget("foo1", "foo2"))
- r.incrbyfloat("foo1", amount=2.0)
- r.incrbyfloat("foo2", amount=3.0)
- print(r.mget("foo1", "foo2"))
20.decr(self, name, amount=1) 自减 name 对应的值,当 name 不存在时,则创建 name=amount,否则,则自减。参数:name,Redis 的 nameamount, 自减数(整数)
- r.decr("foo4", amount=3) # 递减3
- r.decr("foo1", amount=1) # 递减1
- print(r.mget("foo1", "foo4"))
21.append(key, value) 在 redis name 对应的值后面追加内容参数:key, redis 的 namevalue, 要追加的字符串
- r.append("name", "haha") # 在name对应的值junxi后面追加字符串haha
- print(r.mget("name"))
来源: http://www.linuxidc.com/Linux/2017-12/149449.htm