Spring Boot緩存

概述

??Spring提供了對應(yīng)用程序添加緩存的支持灾馒。從本質(zhì)上講笼呆,將緩存應(yīng)用于方法上,從而根據(jù)緩存中的信息減少執(zhí)行次數(shù)。當(dāng)開發(fā)者調(diào)用一個方法時鸥跟,將方法的參數(shù)和返回值作為Key/Value緩存起來丢郊,當(dāng)再次調(diào)用這個方法時,如果緩存中存在對應(yīng)數(shù)據(jù)医咨,就從緩存中獲取數(shù)據(jù)枫匾,否則再去執(zhí)行該方法。

支持

Spring并沒有提供緩存的實現(xiàn)拟淮,而是提供了一套Api干茉,可以自由選擇緩存的實現(xiàn)。目前Spring Boot支持的緩存有如下幾種(Spring Boot會按順序檢測以下提供的程序):

  • Generic
  • JCache(JSR-107)(EhCache 3, Hazelcast, Infinispan, and others)
  • EhCache 2.x
  • Hazelcast
  • Infinispan
  • Couchbase
  • Readis
  • Caffeine
  • Simple

可以通過設(shè)置屬性來指定提供緩存的程序很泊。

無論使用哪種緩存實現(xiàn)不同的只是緩存配置角虫,使用的緩存注解是一致的

注解 介紹
@EnableCaching 啟用S??pring的注釋驅(qū)動的緩存管理功能
@CacheConfig 當(dāng)此批注出現(xiàn)在給定的類上時,它為該類中定義的任何緩存操作提供一組默認(rèn)設(shè)置委造。
@Cacheable 表示可以緩存調(diào)用方法(或類中的所有方法)結(jié)果的注釋戳鹅。每次調(diào)用指定方法時,將進(jìn)行緩存行為昏兆,檢查是否已緩存該方法參數(shù)和結(jié)果枫虏。如果在緩存中找不到鍵的值,則將調(diào)用目標(biāo)方法并將返回的值存儲在關(guān)聯(lián)的緩存中爬虱。
@CacheEvict 表示方法(或類上的所有方法)觸發(fā)緩存逐出操作的注解隶债。
@CachePut 表示方法(或類上的所有方法)觸發(fā)緩存放置操作的注釋。
@Caching 此批注可用作元批注跑筝,以創(chuàng)建具自定義組合批注死讹。

一、Ehcache 2.x 緩存

在項目的pom.xml文件中添加以下依賴:
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>
添加緩存配置文件

如果存在Ehcache的依賴曲梗,并且在classpath下有名為ehcache.xml的文件回俐,那么EhCacheCacheManager將會自動作為緩存的提供者。因此稀并,在resources目錄下創(chuàng)建ehcache.xml文件作為Ehcach緩存的配置文件仅颇。

如果未配置ehcache.xml,則Ehcache依賴包下的ehcache-failsafe.xml是ehcache的默認(rèn)配置碘举。

<ehcache>
    <!--diskStore元素是可選的忘瓦。-->
    <!--如果為任何緩存啟用了overflowToDisk或diskPersistent,則必須對其進(jìn)行配置。-->
    <!--diskStore只有一個屬性 - path耕皮。這是將在其中創(chuàng)建.data和.index文件的目錄路徑境蜕。-->
    <!--如果路徑是Java系統(tǒng)屬性,則將其替換為正在運行的VM中的值-->
    <!--user.home - 用戶的主目錄-->
    <!--user.dir - 用戶的當(dāng)前工作目錄-->
    <!--java.io.tmpdir - 默認(rèn)臨時文件路徑-->
    <!--ehcache.disk.store.dir - 在命令行上指定的系統(tǒng)屬性(例:java -Dehcache.disk.store.dir=/u01/myapp/diskdir)-->
    <!--子目錄可以在屬性后指定 例:java.io.tmpdir/cache-->
    <diskStore path="java.io.tmpdir/cache"/>

    <!--強(qiáng)制性默認(rèn)緩存配置-->
    <!--這些設(shè)置將應(yīng)用于使用CacheManager.add(String cacheName)創(chuàng)建的緩存凌停。-->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <!--localTempSwap - 該策略允許緩存在緩存操作期間使用本地磁盤粱年。磁盤存儲是臨時的,并在重新啟動后清除罚拟。-->
        <!--當(dāng)策略為"none"時台诗,所有緩存都保留在內(nèi)存中(磁盤無溢出,磁盤無持久性)赐俗。-->
        <persistence strategy="localTempSwap"/>
    </defaultCache>

    <cache name="student"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="120"
           timeToLiveSeconds="120"
           overflowToDisk="true"
           diskPersistent="true"
           diskExpiryThreadIntervalSeconds="600"/>
</ehcache>
緩存配置 <cache/>:
屬性 介紹
name 設(shè)置緩存的名稱拉队,用于標(biāo)識緩存。
maxElementsInMemory 設(shè)置在內(nèi)存中創(chuàng)建的最大對象數(shù)(0 ==無限制)阻逮。
maxElementsOnDisk 設(shè)置將在DiskStore中維護(hù)的最大對象數(shù)粱快。默認(rèn)值為零,表示無限制叔扼。
eternal 設(shè)置元素是否一直存在事哭。如果為true,超時將被忽略瓜富。
overflowToDisk 設(shè)置當(dāng)內(nèi)存中的緩存達(dá)到maxInMemory限制時元素是否可以溢出到磁盤慷蠕。
timeToIdleSeconds 設(shè)置元素過期之前的空閑時間,即緩存創(chuàng)建以后最后一次訪問緩存的時間到超時失效時的時間間隔食呻。值為0表示無窮大流炕,默認(rèn)值為0。
timeToLiveSeconds 設(shè)置元素過期之前的生存時間仅胞,即從創(chuàng)建時間到元素過期之間的間隔每辟。值為0表示一直存在,默認(rèn)值為0干旧。
diskPersistent 磁盤存儲在虛擬機(jī)重新啟動后是否仍然存在渠欺,默認(rèn)值為false。
diskExpiryThreadIntervalSeconds 做元素失效監(jiān)測以及清除工作的線程運行間隔時間椎眯,默認(rèn)值為120秒挠将。
diskSpoolBufferSizeMB 磁盤緩沖區(qū)大小,默認(rèn)30MB(內(nèi)部以字節(jié)為單位编整,設(shè)置的值轉(zhuǎn)換為字節(jié)后不可超過正整數(shù)表示范圍)舔稀。
memoryStoreEvictionPolicy 達(dá)到maxElementsInMemory限制后,將強(qiáng)制執(zhí)行清除策略掌测。默認(rèn)策略是最近最少使用(LRU)内贮,其他可用策略先進(jìn)先出(指定為FIFO)和不常用(指定為LFU)。
開啟緩存

在項目的入口類上添加@EnableCaching注解開啟緩存。

@EnableCaching
@SpringBootApplication
public class EhcacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(EhcacheApplication.class, args);
    }

}
創(chuàng)建數(shù)據(jù)接口
@Service
@CacheConfig(cacheNames = "student")
public class StudentService {

    @Resource
    private StudentMapper studentMapper;

    @Cacheable
    public Student findById(Integer id) {
        Student student = studentMapper.findById(id);
        System.out.println("查詢 :" + JSON.toJSONString(student));
        return student;
    }

    @CachePut(key = "#student.id")
    public Student insert(Student student) throws Exception {
        int status = studentMapper.insert(student);
        if (status == 0) {
            throw new Exception("Insert failed");
        }
        System.out.println("插入 :" + JSON.toJSONString(student));
        return student;
    }

    @CacheEvict(key = "#student.id")
    public Student delete(Student student) throws Exception {
        int status = studentMapper.delete(student);
        if (status == 0) {
            throw new Exception("Delete failed");
        }
        System.out.println("刪除 :" + JSON.toJSONString(student));
        return student;
    }

    @CachePut(key = "#student.id")
    public Student update(Student student) throws Exception {
        int status = studentMapper.update(student);
        if (status == 0) {
            throw new Exception("Update failed");
        }
        System.out.println("更新 :" + JSON.toJSONString(student));
        return student;
    }

}
創(chuàng)建請求接口
@RestController
@RequestMapping("/std")
public class StudentController {

    @Resource
    private StudentService studentService;

    /**
     * 查詢
     */
    @RequestMapping("/sel")
    public String findById(Student student) {
        Map<String, Object> msg = new HashMap<>();
        try {
            student = studentService.findById(student.getId());
            msg.put("status", 200);
            msg.put("result", student);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return JSON.toJSONString(msg);
    }

    /**
     * 插入
     */
    @RequestMapping("/ins")
    public String insert(Student student) {
        Map<String, Object> msg = new HashMap<>();
        try {
            studentService.insert(student);
            msg.put("status", 200);
            msg.put("message", "插入成功");
        } catch (Exception e) {
            msg.put("status", 400);
            msg.put("message", "插入失敗");
        }
        return JSON.toJSONString(msg);
    }


    /**
     * 刪除
     */
    @RequestMapping("/del")
    public String delete(Student student) {
        Map<String, Object> msg = new HashMap<>();
        try {
            studentService.delete(student);
            msg.put("status", 200);
            msg.put("message", "刪除成功");
        } catch (Exception e) {
            msg.put("status", 400);
            msg.put("message", "刪除失敗");
        }
        return JSON.toJSONString(msg);
    }

    /**
     * 更新
     */
    @RequestMapping("/upd")
    public String update(Student student) {
        Map<String, Object> msg = new HashMap<>();
        try {
            studentService.update(student);
            msg.put("status", 200);
            msg.put("message", "更新成功");
        } catch (Exception e) {
            msg.put("status", 400);
            msg.put("message", "更新失敗");
        }
        return JSON.toJSONString(msg);
    }

}
測試

向數(shù)據(jù)庫中添加數(shù)據(jù):

(一) 查詢

連續(xù)訪問查詢接口頁面并觀察輸出信息:

查詢
控制臺

根據(jù)輸出信息發(fā)現(xiàn)夜郁,在瀏覽器中多次獲取數(shù)據(jù)什燕,數(shù)據(jù)查詢方法只執(zhí)行了一遍。

(二) 更新

訪問更新接口:

更新

再次訪問查詢接口:

查詢

觀察控制臺:


控制臺

發(fā)現(xiàn)訪問更新接口后再次訪問查詢接口竞端,查詢接口并沒有再次從數(shù)據(jù)庫獲取數(shù)據(jù)屎即,而是從緩存中獲取,所以更新接口返回的結(jié)果會覆蓋指定參數(shù)鍵的緩存事富。

(三) 插入

訪問插入接口:

插入

訪問查詢接口:

查詢

觀察控制臺:

控制臺

發(fā)現(xiàn)插入數(shù)據(jù)后再次查詢并沒有從數(shù)據(jù)庫中獲取數(shù)據(jù)技俐,而是從緩存中獲取。因為插入時對參數(shù)和返回的結(jié)果進(jìn)行了緩存赵颅。

(四) 刪除

訪問刪除接口:

刪除

訪問查詢接口:

查詢

觀察控制臺:

控制臺

發(fā)現(xiàn)訪問刪除接口后數(shù)據(jù)庫中的數(shù)據(jù)被刪除虽另,再次訪問查詢接口進(jìn)行查詢發(fā)現(xiàn)觸發(fā)了查詢方法暂刘,說明刪除數(shù)據(jù)時緩存同時也被刪除了饺谬。

二、Redis 單機(jī)緩存

和Ehcache一樣谣拣,如果在classpath下存在Redis并且Redis已經(jīng)配置好募寨,此時會默認(rèn)使用RedisCacheManager作為緩存的提供者。

在項目的pom.xml文件中添加以下依賴(與之前的依賴相比不同的只是緩存的提供者):

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>

添加項目配置:

spring:
  datasource:
    url: jdbc:mysql://xxx.xxx.xxx.xxx/user
    username: xxxx
    password: xxxxxx

  # 緩存配置
  cache:
    # 配置緩存名森缠,多個緩存可使用逗號分隔(one,two)
    cache-names: student
    # 緩存存在時間
    redis:
      time-to-live: 120s
  redis:
    host: xxx.xxx.xxx.xxx
    port: xxxx

之后的流程與之前一致就不在闡述了拔鹰。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市贵涵,隨后出現(xiàn)的幾起案子列肢,更是在濱河造成了極大的恐慌,老刑警劉巖宾茂,帶你破解...
    沈念sama閱讀 222,946評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓷马,死亡現(xiàn)場離奇詭異,居然都是意外死亡跨晴,警方通過查閱死者的電腦和手機(jī)欧聘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來端盆,“玉大人怀骤,你說我怎么就攤上這事』烂睿” “怎么了蒋伦?”我有些...
    開封第一講書人閱讀 169,716評論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長焚鹊。 經(jīng)常有香客問我凉敲,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,222評論 1 300
  • 正文 為了忘掉前任爷抓,我火速辦了婚禮势决,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蓝撇。我一直安慰自己果复,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,223評論 6 398
  • 文/花漫 我一把揭開白布渤昌。 她就那樣靜靜地躺著虽抄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪独柑。 梳的紋絲不亂的頭發(fā)上迈窟,一...
    開封第一講書人閱讀 52,807評論 1 314
  • 那天,我揣著相機(jī)與錄音忌栅,去河邊找鬼车酣。 笑死,一個胖子當(dāng)著我的面吹牛索绪,可吹牛的內(nèi)容都是我干的湖员。 我是一名探鬼主播,決...
    沈念sama閱讀 41,235評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼瑞驱,長吁一口氣:“原來是場噩夢啊……” “哼娘摔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起唤反,我...
    開封第一講書人閱讀 40,189評論 0 277
  • 序言:老撾萬榮一對情侶失蹤凳寺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后彤侍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肠缨,經(jīng)...
    沈念sama閱讀 46,712評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,775評論 3 343
  • 正文 我和宋清朗相戀三年拥刻,在試婚紗的時候發(fā)現(xiàn)自己被綠了怜瞒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,926評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡般哼,死狀恐怖吴汪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蒸眠,我是刑警寧澤漾橙,帶...
    沈念sama閱讀 36,580評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站楞卡,受9級特大地震影響霜运,放射性物質(zhì)發(fā)生泄漏脾歇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,259評論 3 336
  • 文/蒙蒙 一淘捡、第九天 我趴在偏房一處隱蔽的房頂上張望藕各。 院中可真熱鬧,春花似錦焦除、人聲如沸激况。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乌逐。三九已至,卻和暖如春创葡,著一層夾襖步出監(jiān)牢的瞬間浙踢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評論 1 274
  • 我被黑心中介騙來泰國打工灿渴, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留洛波,地道東北人。 一個月前我還...
    沈念sama閱讀 49,368評論 3 379
  • 正文 我出身青樓逻杖,卻偏偏與公主長得像奋岁,于是被迫代替她去往敵國和親思瘟。 傳聞我的和親對象是個殘疾皇子荸百,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,930評論 2 361