一、到目前为止(jedis-2.2.0.jar),在Jedis中其实并没有提供这样的API对对象,或者是List对象的直接缓存,即并没有如下类似的API
jedis.set(String key, Object value)
jedis.set(String key, List<M> values)
而更多的API是类似于 jedis.set(String key, String value)或者jedis.set(String key, String ... value)
那如果我们想缓存对象,怎么办呢?
二、通过研究Jedis的API,我们发现其提供了这样的API
jedis.set(byte[], byte[]),
通过这个API,很显然我们能够实现
jedis.set(String key, Object value)
jedis.set(String key, List<M> values)
我们需要关注的就是在cache的时候将Object和List对象转换成字节数组并且需要提供将字节数组转换成对象返回。
关于Serializable接口的类中的serialVersionUID:
serialVersionUID是long类型的。在Eclipse中有两种生成方式:
默认的是1L:
private static final long serialVersionUID = 1L;
另外一个则是根据类名、接口名、成员方法以及属性等生成一个64位的哈希字段:
private static final long serialVersionUID = 3969438177161438988L;
serialVersionUID主要是为了解决对象反序列化的兼容性问题。
如果没有提供serialVersionUID,对象序列化后存到硬盘上后,再增加或减少类的filed。这样,当反序列化时,就会出现Exception,造成不兼容问题。
但当serialVersionUID相同时,它就会将不一样的field以type的缺省值反序列化。这样就可以避开不兼容问题了。
先设计一个接口:
public interface SerializeTranscoder {
public byte[] serialize(Object value);
public Object deserialize(byte[] in);
}
建一个普通对象:
import java.io.Serializable;
public class User implements Serializable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
再设计一个实现类:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ObjectTranscoder implements SerializeTranscoder {
private ObjectTranscoder() {
}
private static ObjectTranscoder obj = new ObjectTranscoder();
public static ObjectTranscoder getInstance() {
return obj;
}
@Override
public byte[] serialize(Object value) {
if (value == null) {
throw new NullPointerException("Can't serialize null");
}
byte[] rv=null;
ByteArrayOutputStream bos = null;
ObjectOutputStream os = null;
try {
bos = new ByteArrayOutputStream();
os = new ObjectOutputStream(bos);
os.writeObject(value);
os.close();
bos.close();
rv = bos.toByteArray();
} catch (IOException e) {
throw new IllegalArgumentException("Non-serializable object", e);
} finally {
try {
if(os!=null)os.close();
if(bos!=null)bos.close();
}catch (Exception e2) {
e2.printStackTrace();
}
}
return rv;
}
@Override
public Object deserialize(byte[] in) {
Object rv=null;
ByteArrayInputStream bis = null;
ObjectInputStream is = null;
try {
if(in != null) {
bis=new ByteArrayInputStream(in);
is=new ObjectInputStream(bis);
rv=is.readObject();
is.close();
bis.close();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(is!=null)is.close();
if(bis!=null)bis.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return rv;
}
public static void main(String args[]) {
List<Map<String, Object>> l1 = new ArrayList<Map<String, Object>>();
Map<String, Object> m1 = new HashMap<String, Object>();
m1.put("name", "andy");
m1.put("age", 20);
l1.add(m1);
Map<String, Object> m2 = new HashMap<String, Object>();
m2.put("name", "lucy");
m2.put("age", 30);
l1.add(m2);
List<Map<String, Object>> l2 = (List<Map<String, Object>>)ObjectTranscoder.getInstance().deserialize(ObjectTranscoder.getInstance().serialize(l1));
System.out.println(l2.size());
System.out.println(((Map<String, Object>)l2.get(0)).get("name"));
System.out.println(((Map<String, Object>)l2.get(0)).get("age"));
List<Object> l3 = new ArrayList<Object>();
User u1 = new User();
u1.setName("andy");
u1.setAge(20);
User u2 = new User();
u2.setName("lucy");
u2.setAge(30);
l3.add(u1);
l3.add(u2);
List<Object> l4 = (List<Object>)ObjectTranscoder.getInstance().deserialize(ObjectTranscoder.getInstance().serialize(l3));
System.out.println(l4.size());
System.out.println(((User)l4.get(0)).getName());
System.out.println(((User)l4.get(0)).getAge());
}
}
前几天被问到这样一个问题,redis怎么存对象,平时也没怎么注意,只知道redis存字符之类的,不过就是根据键存取值,不过对象的话还是不同的
首先来了解一下为什么要实现序列化
为什么要实现序列化接口
当一个类实现了Serializable接口(该接口仅为标记接口,不包含任何方法定义),表示该类可以序列化.序列化的目的是将一个实现了Serializable接口的对象转换成一个字节序列,可以。 把该字节序列保存起来(例如:保存在一个文件里),以后可以随时将该字节序列恢复为原来的对象。甚至可以将该字节序列放到其他计算机上或者通过网络传输到其他计算机上恢复,只要该计 算机平台存在相应的类就可以正常恢复为原来的对象。 实现:要序列化一个对象,先要创建某些OutputStream对象,然后将其封装在一个ObjectOutputStream对象内,再调用writeObject()方法即可序列化一个对象;反序列化也类似。
注意:使用对象流写入到文件是不仅要保证该对象是序列化的,而且该对象的成员对象也必须是序列化的
关于Serializable接口的类中的serialVersionUID:
serialVersionUID是long类型的。在Eclipse中有两种生成方式:
默认的是1L:
private static final long serialVersionUID = 1L;
另外一个则是根据类名、接口名、成员方法以及属性等生成一个64位的哈希字段:
private static final long serialVersionUID = 3969438177161438988L;
serialVersionUID主要是为了解决对象反序列化的兼容性问题。
如果没有提供serialVersionUID,对象序列化后存到硬盘上之后,再增加或减少类的filed。这样,当反序列化时,就会出现Exception,造成不兼容问题。
但当serialVersionUID相同时,它就会将不一样的field以type的缺省值反序列化。这样就可以避开不兼容问题了。
以上方式只能恢复成Java对象,如果想要恢复成其他对象(如C++对象),那就要将Java对象转换为XML格式,这样可以使其被各种平台和各种语言使用。可以使用随JDK一起发布的javax.xam.*类库,或者使用开源XOM类库(可以从www.xom.nu下载并获得文档)。
接下来看看redis是怎么存对象的
/**
* 设置 list
* @param <T>
* @param key
* @param value
*/
public <T> void setList(String key ,List<T> list){
try {
getJedis().set(key.getBytes(),ObjectTranscoder.serialize(list));
} catch (Exception e) {
logger.error("Set key error : "+e);
}
}
/**
* 获取list
* @param <T>
* @param key
* @return list
*/
public <T> List<T> getList(String key){
String bKey = buildKey(key);
if(getJedis() == null || !getJedis().exists(key.getBytes())){
return null;
}
byte[] in = getJedis().get(key.getBytes());
List<T> list = (List<T>) ObjectTranscoder.deserialize(in);
return list;
}
/**
* 设置 map
* @param <T>
* @param key
* @param value
*/
public <T> void setMap(String key ,Map<String,T> map){
try {
getJedis().set(key.getBytes(),ObjectTranscoder.serialize(map));
} catch (Exception e) {
logger.error("Set key error : "+e);
}
}
/**
* 获取list
* @param <T>
* @param key
* @return list
*/
public <T> Map<String,T> getMap(String key){
String bKey = buildKey(key);
if(getJedis() == null || !getJedis().exists(key.getBytes())){
return null;
}
byte[] in = getJedis().get(key.getBytes());
Map<String,T> map = (Map<String, T>) ObjectTranscoder.deserialize(in);
return map;
}