分页缓存预加载算法:
将数据分页(块)存储在缓存,这个页(块),一般大于应用实际请求的页面大小,分页(块)缓存的加载采取预加载方式,即在应用分页请求还没读到分页(块)的最后一页数据时,即预先加载下一页的缓存。这样做有点如下:(1)减少DB读取次数。(2)减少缓存传输数据大小。(3)预加载分页缓存则避免应用请求超时。
令:
total : 记录总数
cm :缓存大小,每一次缓存的记录条数
cp :当前缓存页数
n :一次请求多少条数
p :当前请求第几页
x :提前几页开始预加载缓存
bucket:缓存第几页(块)
begin : 从缓存的第几条开始取
threshold : 触发读取DB条件。
令:cm >= n+ n*x 保证缓存数据可供至少请求一次才触发预加载
则:
bucket = (p * n) / cm + 1
begin = (p - 1) * n + 1
threshold :((p * n) % cm + n * x) >= cm
算法描述:
- 初始化加载缓存,从DB中取cm条记录存入缓存。
- 应用分页请求时,如果:
- (p * n) % cm >= n,在第(p * n) / cm + 1页缓存从((p - 1) * n ) % cm + 1 条开始取n条记录返回
- (p * n) % cm < n , 请求跨了两个(页)缓存,需要在两个缓存中各取一部分数据拼接返回。在缓存从 (p * n) / cm 页缓存中从 ((p - 1)*n - 1) % cm + 1条开始取 n - (p * n) % cm 条加上,在缓存从(p * n) / cm + 1页缓存中从第1条开始取(p * n) % cm条合并返回。
- 如果 (p * n) % cm + n * x >= cm ,触发预加载,即从DB中加载cm条记录至缓存。
- 结束。
算法demo:
package com.xx.lt;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Jenkin.K on 17/6/1.
*/
public class PageCache {
Map<Integer,Cache> cacheMemory = new HashMap<Integer, Cache>();
Map<Integer, Record> dbData;
int cm = 50; //缓存大小
int bucket ; //当前缓存页
int begin ; //从缓存的第几条开始取
int n ; //一次请求多少条
int p ; //当前请求第几页
int x = 2; //提前
public static void main(String args[]){
PageCache pageCache = new PageCache();
pageCache.dbData = pageCache.initData();
pageCache.cacheMemory.put(1, pageCache.loadCache(pageCache.cm, 1));
int total = 1000;
int pageSize = 6;
for(int i = 0; i < total/pageSize - 1; i++) {
System.out.println("get "+ (i+1) +" page :" );
pageCache.getPage(i + 1, pageSize);
}
System.out.println(pageCache.cacheMemory);
}
private Map<Integer, Record> initData(){
Map<Integer, Record> data = new HashMap<Integer, Record>();
for(int i = 0; i < 1000; i++){
data.put(i+1, new Record(i+1));
}
return data;
}
public void getPage(int p, int n){
Map<Integer, Record> page = new HashMap<Integer, Record>();
bucket = (p * n) / cm + 1; //求当前取哪页缓存
begin = ((p -1) * n) + 1;
if((p * n) % cm > n || (p * n) % cm == n){ //没跨缓存
page = getFromCache(bucket, begin, n, page);
}else { //跨缓存
page = getFromCache(bucket - 1, begin, n - (p * n) % cm, page);
page = getFromCache(bucket, (bucket-1) * cm + 1, (p * n) % cm, page);
}
if((p * n) % cm > cm - n * x || (p * n) % cm == cm - n * x){
System.out.println("load cache");
cacheMemory.put(bucket + 1, loadCache(cm, bucket + 1));
}
System.out.println("page data : " + page);
}
/**
*
* @param bucket 第几页缓存
* @param begin 从哪个开始取
* @return
*/
private Map<Integer, Record> getFromCache(int bucket, int begin, int n, Map<Integer, Record> page){
Cache cache = cacheMemory.get(bucket);
for(int i = 0; i < n; i++){
Record r = cache.cache.get(begin + i);
page.put(begin + i, r);
}
return page;
}
/**
*
* @param cm 缓存大小
* @param bucket 第几页缓存
* @return
*/
private Cache loadCache(int cm, int bucket){
Cache cache = new Cache();
int deta = cm * (bucket-1) + 1;
for(int i = 0; i < cm; i++){
cache.cache.put(deta + i, dbData.get(deta + i));
}
return cache;
}
class Cache{
Map<Integer, Record> cache = new HashMap<Integer, Record>();
public String toString(){
StringBuffer sb = new StringBuffer();
for(Map.Entry entry : cache.entrySet()){
sb.append(entry.getKey() + ":" + entry.getValue() + ",");
}
return String.valueOf(sb);
}
}
class Record{
Object value;
Record(Object o){
value = o;
}
public String toString(){
return String.valueOf(value);
}
}
}