iBatis中LRU缓存的问题
下载了iBatis的2.3.4版本,部署了自带的jpetstore,开始研究代码,看到iBatis的LRU缓存部分的时候,觉得iBatis的LRU缓存实现的太囧了:用一个HashMap保存要cache的数据,然后又用了一个LinkedList来保存key,每次从缓存中取数据的时候,都要从LinkedList中把这个key删掉,然后又重新添加进去,以此来实现LRU算法。代码如下:
private int cacheSize;
private Map cache;
private List keyList;
public LruCacheController() {
this.cacheSize = 100;
this.cache = Collections.synchronizedMap(new HashMap());
this.keyList = Collections.synchronizedList(new LinkedList());
}
public void putObject(CacheModel cacheModel, Object key, Object value) {
cache.put(key, value);//把我们的数据以key-value的形式存放在缓存中
keyList.add(key);//同时在keyList中保存key
if (keyList.size() > cacheSize) {
try {
//如果keyList的size大于cacheSize,那么从keyList和cache中移除第一个,从而实现LRU算法
Object oldestKey = keyList.remove(0);
cache.remove(oldestKey);
} catch (IndexOutOfBoundsException e) {}
}
}
看完代码想了一下,这样做,只是一味的remove(0),怎么能叫LRU缓存呢?而且,map是不允许有相同的key的,而list是可以的,按照iBatis的做法,会不会最后出现map和list不同步的问题?测试了一下,果然有这个问题。测试方法:
把cacheSize设置为2,然后重复调用putOject:
pubObject(cacheModel,”key1″,value1);
pubObject(cacheModel,”key2″,value2);
pubObject(cacheModel,”key1″,value3);
pubObject(cacheModel,”key1″,value4);
按理说,这时缓存中应该有2个数据:{key1=value4},{key2=value2},可实际结果是缓存中只有{key1=value4},我们丢失了{key2=value2},而且cache和keyList中出现了不同步的现象,cache中是{key1=value4},而keyList中则是[1,1]。
已经把这个问题当bug提交给iBatis了,英文不好,也不知道写的对不对,bug地址:http://issues.apache.org/jira/browse/IBATIS-676
