1. 程式人生 > >中小專案中快取的使用(心得)

中小專案中快取的使用(心得)

       在稍大型的專案裡,常常為了解決查詢資料的效率或者是為了減輕資料庫的壓力都會採用新增快取來實現目的。那麼在專案裡我們該如何的新增快取?這裡我分享下我的使用快取方案。

  1. 資料量不大的情況下:
           在要快取的資料量並不是太大的情況下,我們可以選擇進行全量快取。即全部快取到記憶體裡面,然後指定過一段時間對資料進行一次更新。每次呼叫方法獲取資料時都先判斷是否有進行過快取或者是快取是否過期,若有快取且沒過期則可以獲取快取裡面的資料。
/**
 * 獲取快取裡面人員名稱
 */
String getName(String id){
    //呼叫判斷方法
    isCacheLoaded();
    //從快取(Map)裡獲取值,返回
} void isCacheLoaded(){ //判斷快取(Map)是否為空, //為空 載入 load() //不為空判斷上次載入快取的時間到現在是否超過規定的時間 //超過 load() } private static final Object LOCK = new Object(); void load(){ //在這裡若是有較高併發的要求則可以添加個鎖用synchronize就可 loaded = false; synchronized (LOADING_LOCK) { if(!loaded){ //查詢資料庫獲取資料
//放到快取(Map)裡面 loaded = true; } } }

2 . 資料量比較大的情況下
       在這種情況下,通常會使用外部快取或者是內部快取+外部快取相結合使用。兩個相結合的情況一般是這樣:內部快取自然是小而且過期時間快,外部快取過期時間長。那麼在不能進行全量快取的情況下,該怎麼做?
       這時候一般是這樣做:在最開始,內部快取和外部快取都是沒有預先存值的。一個請求過來,查詢某個資料。
               查詢內部快取
                          —>有資料,返回。
                          —>沒有資料,查詢外部快取
                                                  —>外部快取有資料,得到,存入內部快取,返回資料。
                                                  —>外部沒有資料,查詢資料庫,
                                                                                   —>資料庫裡面沒有資料,返回null
                                                                                    —>資料庫有資料,存入外部快取,存入內部快取,返回值
           就是這樣的一個流程。

private static Map<Object,Object> lockMap = new ConcurrentHashMap<Object, Object>();
/**
 * 獲取快取裡面人員名稱
 */
String getName(String id){
    //呼叫獲取快取方法
    String result = getCacheData(id);
    if(result==null||result.length()==0){
        //為了避免在高併發的情況下,查詢同個id,
        //在查詢資料庫這一階段的時間停留過久,導致多次穿透快取,查詢多次資料庫
        //所以在這裡新增一個與id關聯的鎖來保證
        Object lock = lockMap.get(id);
        if(lock==null){
            lockMap.put(id,lock = new Object());
        }
        synchronize(lock){
            result = getCacheData(id);//這裡是再次從快取裡獲取資料,避免再次查詢資料庫
            if(result==null||result.length()==0){
                //查詢資料庫,獲取資料
                //存入內部快取,存入外部快取,這樣當其他執行緒進來鎖時,
                //再次查詢快取就有資料了,就不用再次進來查資料了
                lockMap.remove(userId);
            }
        }
    }
}

void getCacheData(String id){
    //先查詢內部快取,內部快取沒有
    //再次查詢外部快取
    //返回值
}

3.其他情況:
        比如我這個專案是可以允許部分髒資料的,那麼可以這樣做,在查詢內外快取後,有資料的情況,但是該資料過期了。那麼返回這個過期的資料,自己立馬起個執行緒去更新快取。這樣下次肯定就是新的資料。這裡也是要添加個判斷是否已經起了個執行緒去資料庫獲取新資料,不然可能會一下子來好多個執行緒做同一件事情,浪費資源。