Python3与redis交互,保存的是字符串,取出来是bytes类型问题
作者:乐事原味~
Python3与redis交互,保存的是字符串,取出来是bytes
原因
在python3中redis连接包读取数据默认返回byte类型。
存进去的是字符串类型的数据,取出来却是字节类型的。
Python2取出来的就是字符串类型的。
import platform import redis if "inux" in platform.system(): print("检测到是服务器环境,启动redis内网链接") IP = "xxx.xx.x.xx" PORT = 6379 else: IP = "xxx.xxx.xxx.xx" PORT = 6379 # 存进去的是字符串类型的数据,取出来却是字节类型的 redisPool1 = redis.ConnectionPool(host=IP, port=PORT, db=1, password="xxxxxxx") if __name__ == '__main__': client = redis.Redis(connection_pool=redisPool1 ) client.set("ACCESS_TOKEN", "ABC123456", 60 * 60) token = client.get("ACCESS_TOKEN") print(token) # b'ABC123456' print(type(token)) # <class 'bytes'>
解决方法
连接redis的时候,加上decode_responses=True或者每次取出来都decode一下(太麻烦,不推荐)
import platform import redis if "inux" in platform.system(): print("检测到是服务器环境,启动redis内网链接") IP = "xxx.xx.x.xx" PORT = 6379 else: IP = "xxx.xxx.xxx.xx" PORT = 6379 # 存进去的是字符串类型的数据,取出来也是字符型 redisPool1 = redis.ConnectionPool(host=IP, port=PORT, db=1, password="xxxxxxx", decode_responses=True) if __name__ == '__main__': client = redis.Redis(connection_pool=redisPool1 ) client.set("ACCESS_TOKEN", "ABC123456", 60 * 60) token = client.get("ACCESS_TOKEN") print(token) # ABC123456 print(type(token)) # <class 'str'>
Redis-Python交互:编码、连接、基本命令
在redis-py 3.0之后就不在支持使用传统的‘Redis’客户端类了。
StrictRedis 现在只是 Redis 的一个别名,现在这个连接更加python化。
例如,使用redis的字符串操作 setbit 和 getbit 来统计用户活跃天数:
''' 用Redis统计用户上线次数 理解: A用户 100010001000001 //活跃了4天 B用户 111111111111111 //每日必到 ''' import redis from ..password import redis_passwd # 连接Redis,选择 db0 r = redis.Redis(host='localhost', port=6379, password=redis_passwd, db=0) # A用户,一年中,每3天上线一次 for i in range(0, 365, 3): r.setbit('usera', i, 1) # B用户 每10天上线一次 for i in range(0, 365, 10): r.setbit('userb', i, 1) # 用户列表 # "Returns a list of keys matching ``pattern``" userList = r.keys('user*') print(userList) Au = [] Nau = [] # 判断是否为活跃用户,(用户,登录天数) for u in userList: logincount = r.bitcount(u) if logincount > 100: Au.append((u, logincount)) else: Nau.append((u, logincount)) for u in Au: print(f'用户{u[0]}: 活跃用户, 共登录{u[1]}天') for u in Nau: print(f'用户{u[0]}: 非活跃用户, 共登录{u[1]}天')
编码
PubSub对象遵循与其创建的客户端实例相同的编码方式。在发送到Redis之前,将使用客户端上指定的字符集对任何使用unicode编码的通道或模式进行编码。
如果客户端的decode_responses标志设置为False(默认值),则消息字典中的channel,pattern和data值将是字节字符串(Python2的str,Python3的bytes)。
如果客户端的decode_responses为True,则它们值将使用客户端的字符集自动解码为unicode字符串。
默认,bytes类型:
>>> import redis >>> r = redis.Redis(host='localhost', port=6379, password='***') >>> r.set('str', 'time') True >>> ret = r.get('name') >>> print(ret, type(ret)) b'Redis' <class 'bytes'> >>>
修改为str:
>>> import redis >>> r = redis.Redis(host='localhost', port=6379, password='***', decode_responses=True) >>> r.set('str', 'time') True >>> ret = r.get('name') >>> print(ret, type(ret)) Redis <class 'str'>
默认redis入库编码是utf-8,如果要修改的话,需要指明 charset和 decode_responsers 为True。
使用GBK编码:
>>> r2 = redis.Redis(host='localhost', port=6379, password='***', charset='GBK' ,decode_responses=True) >>> r2.set('greet', '你好') True >>> r2.get('greet') '你好'
连接池
redis使用connection pool来管理对一个redis server 的所有连接,避免每次建立、释放连接的开销。
默认,每个Redis实例都会维护一个自己的连接池。
可以直接建立一个连接池,然后作为参数创建Redis实例,这样就可以实现多个Redis实例共享一个连接池。
""" 连接池 """ import redis from ..password import redis_passwd pool = redis.ConnectionPool(host='localhost', port=6379, db=0, password=redis_passwd) r = redis.Redis(connection_pool=pool) r.set('name', 'Redis') print(r.get('name')) # 输出结果 b'Redis'
连接方式
ConnectionPools管理一组Connection实例。
redis-py有两种类型的连接。默认值连接方式是基于TCP套接字的常规连接。
UnixDomainSocketConnection允许在与服务器相同的设备上运行的客户端通过unix域套接字进行连接。
要使用UnixDomainSocketConnection连接,只需将unix_socket_path参数传递给unix域套接字文件,该参数是一个字符串。
此外,请确保在redis.conf文件中定义了unixsocket参数,默认注释掉了。
# Unix socket. # # Specify the path for the Unix socket that will be used to listen for # incoming connections. There is no default, so Redis will not listen # on a unix socket when not specified. # # unixsocket /var/run/redis/redis-server.sock # unixsocketperm 700
>>> r = redis.Redis(unix_socket_path='/tmp/redis.sock')
操作
key操作
delete(self, *names)
:删除键dump(self, name)
:序列化给定 key ,并返回被序列化的值exists(self, *names)
:检查给定 key 是否存在。expire(self, name, time)
:为给定 key 设置过期时间,以秒计,time为整数Python timedelta 对象。expireat(self, name, when)
:EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置过期时间。 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)或python datetime对象pexpire(self, name, time)
:类似expire, 时间以毫秒计pexpireat(self, name, when)
:类似expireat, 时间以毫秒计keys(self, pattern=’*’)
:查找所有符合给定模式( pattern)的 keymove(self, name, db)
:将当前数据库的 key 移动到给定的数据库 db 当中persist(self, name)
:移除 key 的过期时间,key 将持久保持。pttl(self, name)
:以毫秒为单位返回 key 的剩余的过期时间ttl(self, name)
:以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)randomkey(self)
:从当前数据库中随机返回一个 keyrename(self, src, dst)
:修改 key 的名称renamenx(self, src, dst)
:当dst不存在时,可以使用它作为src的名字type(self, name)
:返回 key 所储存的值的类型
服务器操作
bgrewriteaof(self)
:异步执行一个 AOF(AppendOnly File) 文件重写操作bgsave(self)
:在后台异步保存当前数据库的数据到磁盘client_kill(self, address)
:关闭客户端连接client_list(self, _type=None)
:获取连接到服务器的客户端连接列表client_getname(self)
:获取连接的名称client_id(self)
:获取当前连接的idclient_setname(self, name)
:设置当前连接的名称client_pause(self, timeout)
:在指定时间内终止运行来自客户端的命令(毫秒)client_unblock(self, client_id, error=False)
:解除指定连接id的客户端阻塞config_get, config_set,config_rewrite
:读写redis.conf配置文件config_resetstat(self)
:重置 INFO 命令中的某些统计数据dbsize(self)
:返回当前数据库的 key 的数量debug_object(self, key)
:获取 key 的调试信息echo(self, value)
:打印字符串flushall(self, asynchronous=False)
:清空所有数据库flushdb(self, asynchronous=False)
:清空当前数据库info(self, section=None)
:获取 Redis 服务器的各种信息和统计数值lastsave(self)
:返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示
save(self):同步保存数据到硬盘
ping(self)
:查看服务是否运行migrate
(self, host, port, keys, destination_db, timeout,copy=False, replace=False, auth=None): 数据库迁移shutdown
(self, save=False, nosave=False):异步保存数据到硬盘,并关闭服务器slaveof
(self, host=None, port=None):将当前服务器转变为指定服务器的从属服务器(slave server)slowlog_get
(self, num=None):管理 redis 的慢日志wait
(self, num_replicas, timeout):Redis同步复制
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。