分頁緩存預加載算法:
將數據分頁(塊)存儲在緩存,這個頁(塊),一般大於應用實際請求的頁面大小,分頁(塊)緩存的加載采取預加載方式,即在應用分頁請求還沒讀到分頁(塊)的最后一頁數據時,即預先加載下一頁的緩存。這樣做有點如下:(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); } } }