[Python 实战] - No.14 Python-Redis中的编码问题

Python-Redis中的编码问题

最近在写代码的时候,因为redis的编码的问题,debug了一天,最后终于搞清楚了python-redis中遇到的那些坑。在这里记录一下:

python中如何连接redis:

在python中,我们使用python-redis库来连接redis数据库。我们采用如下方式连接redis:

import redis
pool = redis.ConnectionPool(host='localhost', port=6379)
r = redis.Redis(connection_pool=pool)

我们尝试向redis中添加两个键值对:

r.set('bob','123456')
r.set('alice','987654')
print(r.keys())

'''output
[b'alice', b'bob']
'''

我们会发现,打印出的key数组,每个字符串前面加了一个b。在python3.x中,这表示这个字符串是bytes。

如果我们希望判断'bob'是否在数据库中,并打印bob对应的值,通常我们会这样做:

if 'bob' in r.keys():
    print(r.get('bob'))
else:
    print('No such key!')
    
print(r.get('bob'))
    
'''output
No such key!
b'123456'
'''

我们会发现,明明我们已经在redis中存储了('bob','123456')键值,但是我们使用get()方法却无法获取到。这是因为:

  • 在redis中,键和值都是以bytes方式存储的,r.keys()返回键也是bytes形式的。
  • 当我们判断str类型的字符串是否在 bytes类型的列表中时,结果是False
  • 由于r.get()函数实现中会有encode()操作,所以r.get()可以接受bytes形式,也可以接受str形式

例如:

r.flushall()
r.set('bob','123456')
r.set('alice','987654')

for k in r.keys():     # r.get() 可以接受bytes()类型的输入
    print(k,r.get(k))
    
if 'bob'.encode('utf-8') in r.keys():
    print(r.get('bob'))
else:
    print('No such key!')
    
k = 'bob'
print("Encode:",k,r.get(k).decode('utf-8')) # r.get()函数也可以直接传入str

'''output
b'alice' b'987654'
b'bob' b'123456'
b'123456'
Encode: bob 123456
'''

总结:

  • 在redis中存储的键值对均为bytes类型
  • 如果我们希望查询某一个str类型的键是否在数据库中,需要使用encode(),将str转换为bytes,看是否在r.keys()中;使用decode将查询出的bytes值转换为str

如果我们总是使用encode和decode来编码-解码键值对,会非常的麻烦。在python中,我们可以通过声明redis连接池的decode_responses字段来对键值对进行默认编码:

import redis
pool = redis.ConnectionPool(host='localhost', port=6379,decode_responses=True)
r = redis.Redis(connection_pool=pool)
r.flushall()

r.set('Monday','Sunny')
r.set('Tuesday','Rainy')

for k in r.keys():
    print(k,r.get(k))
    
'''output
Tuesday Rainy
Monday Sunny
'''

我们发现,当我们声明了decode_responses=True 之后,我们从redis中使用get()和keys()获得的键值对就都是str类型的了。

那么我们是不是一直使用decode_responses=True 就好了呢?为什么redis要将decode_responses默认设置成False呢?。我们分别在两种情况下进行如下操作:

  • 创建一个dict
  • 使用pickle对dict打包存储到redis中
  • 读取dict,并使用pickle加载

不使用decode_responses

import redis
import pickle
pool = redis.ConnectionPool(host='localhost', port=6379)
r = redis.Redis(connection_pool=pool)
r.flushall() # 清空redis

d = {'bob':'123456789','alice':'987654321'}
r.set('my_dict',pickle.dumps(d))
new_d = pickle.loads(r.get('my_dict'))
print(new_d)

'''output
{'bob': '123456789', 'alice': '987654321'}
'''

使用decode_responses

import redis
import pickle
pool = redis.ConnectionPool(host='localhost', port=6379,decode_responses=True)
r = redis.Redis(connection_pool=pool)
r.flushall() # 清空redis

d = {'bob':'123456789','alice':'987654321'}
r.set('my_dict',pickle.dumps(d))
new_d = pickle.loads(r.get('my_dict'))
print(new_d)

'''output
Traceback (most recent call last):
  File "<ipython-input-31-2fd8f3eab4ba>", line 9, in <module>
    new_d = pickle.loads(r.get('my_dict'))
  File "C:\ProgramData\Anaconda3\lib\site-packages\redis\client.py", line 1264, in get
    return self.execute_command('GET', name)
  File "C:\ProgramData\Anaconda3\lib\site-packages\redis\client.py", line 775, in execute_command
    return self.parse_response(connection, command_name, **options)
  File "C:\ProgramData\Anaconda3\lib\site-packages\redis\client.py", line 789, in parse_response
    response = connection.read_response()
  File "C:\ProgramData\Anaconda3\lib\site-packages\redis\connection.py", line 637, in read_response
    response = self._parser.read_response()
  File "C:\ProgramData\Anaconda3\lib\site-packages\redis\connection.py", line 332, in read_response
    response = self.encoder.decode(response)
  File "C:\ProgramData\Anaconda3\lib\site-packages\redis\connection.py", line 133, in decode
    value = value.decode(self.encoding, self.encoding_errors)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte
'''

这是因为,我们使用pickle存储的时候,pickle会将对象dumps成bytes类型的字符串,并且该字符串无法使用utf-8进行decode。由于我们使用了decode_responses, 执行r.get(‘my_dict’)的时候会尝试将pickle dumps的字符串deocde为utf8,所以会抛出异常。

总结:究竟我们什么时候需要使用decode_responses呢?

  • 如果我们redis只是为了存储一些str字符串等键值对,推荐使用decode_responses来避免在代码手动decode
  • 如果在redis使用中,会涉及对象,字典,列表等的存储,不使用decode_responses
  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
redis.windows-service.conf和redis.windows.conf是Redis的配置文件。它们用于指定Redis服务器的参数和设置。引用提到,当直接点击安装目录下的redis-server.exe时,默认加载redis.windows-service.conf的配置。如果想要加载redis.windows.conf的配置,可以在安装目录下运行控制台,输入redis-server redis.windows.conf来加载指定的配置文件。给出了三个建议来使用redis.windows.conf配置文件启动Redis。首先,需要禁用Redis的自启动,并将其设置为手动启动。其次,推荐使用Redis的压缩版而非安装版。最后,通过命令行CMD加载配置文件(redis.windows.conf)来启动Redis提供了完整的实例指令,可以使用redis-server命令来安装Redis服务,并指定配置文件(redis.windows.conf),同时可以设置日志级别和服务名称。123 #### 引用[.reference_title] - *1* [redis.windows-service.conf和redis.windows.conf的区别](https://blog.csdn.net/lizeheng/article/details/126748523)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] - *2* *3* [我们一起来学习redis吧【redis的启动和关闭,配置文件详解】【redis.windows.conf和redis.windows-service](https://blog.csdn.net/qq_46416934/article/details/124153540)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值