分页缓存预加载算法:
将数据分页(块)存储在缓存,这个页(块),一般大于应用实际请求的页面大小,分页(块)缓存的加载采取预加载方式,即在应用分页请求还没读到分页(块)的最后一页数据时,即预先加载下一页的缓存。这样做有点如下:(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); } } }