1. 程式人生 > >SpringBoot學習筆記08——解決Cache快取同類中呼叫失敗問題

SpringBoot學習筆記08——解決Cache快取同類中呼叫失敗問題

問題描述

今天遇到了一個問題,使用快取的情況下,如果在快取服務類方法中呼叫快取的方法會呼叫失敗,就是this.快取方法名,這樣使用就不會從快取中獲取資料,而是直接呼叫快取方法,錯誤示例程式碼如下:

package com.youyou.address.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 這是一個測試快取service
 *
 * @author 劉朋
 * <br/>date 2018-10-24
 */

@Service
public class CacheService {

    @Autowired
    private CacheService cacheService;

    /**
     * 查詢快取,快取的名字是testList,用key來標識
     * @param key
     * @return
     */
    @Cacheable(cacheNames = "testList" , key = "#key")
    public List<String> testCache(String key){
        System.out.println("呼叫了快取方法");
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add(key);
        return list;
    }

    /**
     * 修改快取,快取的名字是testList,用key來標識
     * @param key
     * @return
     */
    @CachePut(cacheNames = "testList" , key = "#key")
    public List<String> testPutCache(String key){
        List<String> stringList = testCache(key);

        List<String> list = new ArrayList<>();
        list.add("1");
        list.add(key);
        return list;
    }
}

上述程式碼就存在問題,呼叫testPutCache()時,系統並不會去查詢testCache()方法快取的資料,而是直接呼叫testCache()方法。

讓我們測試一下:

public String testCache(){
        //第一次中快取中查詢
        List<String> test = cacheService.testCache("test");

        //修改快取中的值
        List<String> test2 = cacheService.testPutCache("test");

        return "";
    }

後臺輸出結果如下:

會輸出兩次“呼叫了快取方法”,顯然時快取的程式碼出現了問題。

後來我查閱了一下資料,明白了其中的緣由,簡單來講,在通過注入物件的形式呼叫方法時,spring會檢測到快取註解,會以aop的形式去執行方法,首先去快取中查詢,如果查詢到資料了,就不再執行改方法。如果時在方法中直接呼叫的話就不能使用aop進行判斷了,所以每次都會執行方法體。

 

解決方法

網上查到的解決方法時這樣的“SpringAOP 無法解決,需要使用 AspectJ 來解決!

這個解決方式博主本人沒有去測試,而是想到了另一個方法簡單易用。

我的思路是:既然我們不能直接呼叫,那麼就用注入的方式來解決這個問題就可以了,呼叫方法的時候使用物件來呼叫不就沒有問題了嗎?

接下來帶著猜想博主進行了測試,測試程式碼如下:

package com.youyou.address.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 這是一個測試快取service
 *
 * @author 劉朋
 * <br/>date 2018-10-24
 */

@Service
public class CacheService {

    @Autowired
    private CacheService cacheService;

    /**
     * 查詢快取,快取的名字是testList,用key來標識
     * @param key
     * @return
     */
    @Cacheable(cacheNames = "testList" , key = "#key")
    public List<String> testCache(String key){
        System.out.println("呼叫了快取方法");
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add(key);
        return list;
    }

    /**
     * 修改快取,快取的名字是testList,用key來標識
     * @param key
     * @return
     */
    @CachePut(cacheNames = "testList" , key = "#key")
    public List<String> testPutCache(String key){
        List<String> stringList = cacheService.testCache(key);

        List<String> list = new ArrayList<>();
        list.add("1");
        list.add(key);
        return list;
    }
}

只是在呼叫testCache()方法時是通過物件進行呼叫的。

執行結果如下:

只打印了一次“呼叫了快取方法”

這說明博主的猜想是正確的。