用Jedis操作存在的问题和根源
上文书我们得知用cli操作Redis是不存在国际化问题的,那为何实际项目中时常会出现因为引入Redis导致大范围非英文字符显示为问号呢?本文我们将使用Java客户端Jedis来操作Redis,进一步分析产生问号现象的可能原因。首先来模拟并测试下Jedis的序列化和反序列化过程吧,通常情况下,这里都是国际化问题的重灾区。
//序列化
public staticbyte[] serialize(Object object) {
ObjectOutputStreamobjectOutputStream = null;
ByteArrayOutputStreambyteArrayOutputStream = null;
try {
byteArrayOutputStream =new ByteArrayOutputStream();
objectOutputStream = newObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object);
byte[] bytes =byteArrayOutputStream.toByteArray();
return bytes;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 反序列化
public staticObject deseialize(byte[] bytes) {
ByteArrayInputStreambyteArrayOutputStream = null;
try {
byteArrayOutputStream =new ByteArrayInputStream(bytes);
ObjectInputStreamobjectInputStream = new ObjectInputStream(byteArrayOutputStream);
return objectInputStream.readObject();
} catch (Exception e) {
System.out.println("deserializeexception");
}
return null;
}
@Test
public voidtestG11nJedis() {
String s = "伯纳多-席尔瓦加盟曼城";
assertEquals(s,deseialize(serialize(s)));
}
测试结果显示——没毛病啊!Redis本身我们已经知晓对国际化的支持是ok的,那只能是Jedis的问题喽?走读下代码,做个地毯式检查吧,毕竟他是一切问题的根源和解药!
@Override
publicList<String> mget(String... fields) {
List<byte[]> arrFields = newArrayList<>();
for (String field : fields) {
arrFields.add(field.getBytes());
}
List<byte[]> results =redisTemplate.execute(
(RedisCallback<List<byte[]>>) connection ->connection.mGet(arrFields.toArray(new byte[arrFields.size()][]))
);
if (results == null) {
return new ArrayList<>();
}
final List<String> ret = newArrayList<>();
results.forEach(result -> {
if (result != null) {
try {
ret.add(new String(result));
} catch(UnsupportedEncodingException e) {
ret.add(null);
}
} else {
ret.add(null);
}
});
return ret;
}
读到mget时,应该已经发现点儿什么了吧?作祟的不是Jedis而是override之后的getBytes和new String,明示charset后问题解决。
反思
我们习惯性的把所有问题归结为新事物的引入,殊不知大部分情况下,经都是好经,不过是我们把它念歪了而已。