如何用python和redis交互呢?
该怎样定义数据存储格式,从而使得数据跨平台使用?当然是Json
并在其他项目中,采用redis缓存进行读取,并由Python进行写入。
这里就简单记录两种语言在读写写Json时候需要注意的点。
Json模块的dumps方法,用于将对象转化为json格式的string对象,
简单看看dumps的定义:
def dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None,
default=None, sort_keys=False, **kw):
str
, int
, float
, bool
, None
),那么执行dumps方法,也不会抛出异常。注意,在Java中,一些成型的库例如jackson,fastjson,都已经帮我们完成了各种转json的骚操作,但是在python中,有些情况则需要手动调用dumps方法来完成转Json。
通常,在一个单一的对象中,使用json.dumps可以完成对象转json操作,但是当多个对象签到,
例如:
class Father(object):
"""dto"""
def __init__(self, Son1, Son2, Son3, Son4):
self.Son1= Son1
self.Son2= Son2
self.Son3= Son3
self.Son4= Son4
这样一来,由于Son*不是python中懂得基本类型,所以我们需要自己重写一个方法,手动调用json.dumps,从而完成转化,否则会报序列化错误:
TypeError: <_io.BytesIO object at 0x7f81c3153728> is not JSON serializable
此时,则需要往Father中,增加一个方法,手动实现对json.dumps的调用即可:
def to_json(self):
return json.dumps(self, default=lambda o: o.__dict__,
sort_keys=True, indent=4)
这样完成就是一个标准的json格式了。
在Java方面,使用Spring Data Redis来管理Redis,通常,在一个项目中,会配置一个RedisTemplete:
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new Jackson2JsonRedisSerializer);
return template;
}
如上,我们可以设置KeySerializer,也可以设置ValueSerilizer,当然,此时,就可以吧Jackson的Serilizer设置进去,此处不过多介绍Jackson的序列化器。另外提一点,如果不设置KeysSerializer,可能会出现乱码情况。
上面的配置,在一个项目中往往不会出现任何问题,因为项目是统一的,从Java对象到Json,是用这个Serializer,从Json到Java对象,也是这个Serializer,但是,如果不同项目中,需要通过Json来传递某些信息,那么就可能会出问题了。
可以了解,其实在Jackson中,有几种Serializer,他们的序列化之后的字符串,虽然是json格式,但是却会有某些区别,
主要有:Jackson2JsonRedisSerializer
和GenericJackson2JsonRedisSerializer
。具体自行理解。
所以在从redis中读取数据时候,需要根据其他语言(例如python)写入的格式,进行解码,必要时需要重写一个Serializer进行解码操作:
例如下面是一个简单地VlueSerializer:
public class PythonJacksonSerializer implements RedisSerializer {
private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
private final Charset charset;
private ObjectMapper objectMapper = new ObjectMapper();
private Class clazz;
public PythonJacksonSerializer(Charset charset, Class clazz) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
this.clazz = clazz;
}
public PythonJacksonSerializer(Class clazz) {
this(Charset.forName("UTF-8"), clazz);
}
@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
try {
return this.objectMapper.writeValueAsBytes(t);
} catch (Exception ex) {
throw new SerializationException("Could not write JSON: " + ex.getMessage(), ex);
}
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length == 0) {
return null;
}
String jsonStr = new String(bytes, charset);
try {
return (T)JSONUtils.json2pojo(jsonStr, this.clazz);
} catch (Exception e) {
LOGGER.error("PythonJacksonSerializer occurs error",e.getMessage());
e.printStackTrace();
}
return null;
}
}