最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Spring數(shù)據(jù)緩存注解@Cacheable、@CachePut、@CacheEvict

 更新時(shí)間:2023年07月14日 11:34:38   作者:仁者樂山智者樂水  
這篇文章主要介紹了詳解Spring數(shù)據(jù)緩存注解@Cacheable、CachePut、@CacheEvict,當(dāng)以一組參數(shù)第一次調(diào)用某個(gè)方法時(shí),返回值會(huì)被保存在緩存中,如果這個(gè)方法再次以相同的參數(shù)進(jìn)行調(diào)用時(shí),這個(gè)返回值會(huì)從緩存中查詢獲取,需要的朋友可以參考下

前言

如果想讓應(yīng)用程序避免一遍遍地為同一個(gè)問(wèn)題推導(dǎo)、計(jì)算或查詢答案的話,緩存是一種很棒的方式。當(dāng)以一組參數(shù)第一次調(diào)用某個(gè)方法時(shí),返回值會(huì)被保存在緩存中,如果這個(gè)方法再次以相同的參數(shù)進(jìn)行調(diào)用時(shí),這個(gè)返回值會(huì)從緩存中查詢獲取。在很多場(chǎng)景中,從緩存查找值會(huì)比其他的方式(比如,執(zhí)行數(shù)據(jù)庫(kù)查詢)成本更低。因此,緩存會(huì)對(duì)應(yīng)用程序的性能帶來(lái)正面的影響。

通過(guò)XML啟用注解驅(qū)動(dòng)的緩存

使用XML的方式配置時(shí),需要使用Spring cache命名空間中的<cache:annotation-driven>元素來(lái)啟用注解驅(qū)動(dòng)的緩存。從本質(zhì)上來(lái)講,其工作方式它是會(huì)創(chuàng)建一個(gè)切面(aspect)并觸發(fā)Spring緩存注解的切點(diǎn)(pointcut)。根據(jù)所使用的注解以及緩存的狀態(tài),這個(gè)切面會(huì)從緩存中獲取數(shù)據(jù),將數(shù)據(jù)添加到緩存之中或者從緩存中移除某個(gè)值。

<cache:annotation-driven>

緩存管理器

緩存管理器是Spring緩存抽象的核心,它能夠與多個(gè)流行的緩存實(shí)現(xiàn)進(jìn)行集成。Spring常見管理器如下表所示:

對(duì)于上表中ConcurrentMapCacheManager,這是一個(gè)簡(jiǎn)單的緩存管理器使用java.util.concurrent.ConcurrentHashMap作為其緩存存儲(chǔ)。它非常簡(jiǎn)單,因此對(duì)于開發(fā)、測(cè)試或基礎(chǔ)的應(yīng)用來(lái)講,這是一個(gè)很不錯(cuò)的選擇。但它的緩存存儲(chǔ)是基于內(nèi)存的,所以它的生命周期是與應(yīng)用關(guān)聯(lián)的,對(duì)于生產(chǎn)級(jí)別的大型企業(yè)級(jí)應(yīng)用程序,這可能并不是理想的選擇。

基于SimpleCacheManager的XML配置示例1

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:cache="http://www.springframework.org/schema/cache" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
    <cache:annotation-driven/>
    <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
        <property name="caches">
            <set>
                <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="users"/>
            </set>
        </property>
    </bean>
</beans

為方法添加注解以支持緩存

如前文所述,Spring的緩存抽象在很大程度上是圍繞切面構(gòu)建的。在Spring中啟用緩存時(shí),會(huì)創(chuàng)建一個(gè)切面,它觸發(fā)一個(gè)或更多的Spring的緩存注解。下表列出了Spring所提供的緩存注解。

填充緩存

可以看到,@Cacheable和@CachePut注解都可以填充緩存,但是它們的工作方式略有差異。

@Cacheable首先在緩存中查找條目,如果找到了匹配的條目,那么就不會(huì)對(duì)方法進(jìn)行調(diào)用了。如果沒有找到匹配的條目,方法會(huì)被調(diào)用并且返回值要放到緩存之中。而@CachePut并不會(huì)在緩存中檢查匹配的值,目標(biāo)方法總是會(huì)被調(diào)用,并將返回值添加到緩存之中。@Cacheable和@CachePut有一些屬性是共有的,如下表所示:

在最簡(jiǎn)單的情況下,在@Cacheable和@CachePut的這些屬性中,只需使用value屬性指定一個(gè)或多個(gè)緩存即可。例如,考慮UserDao的findById(Integer id)方法。在初始保存之后,User數(shù)據(jù)表就不會(huì)再發(fā)生變化了。如果有的用戶會(huì)被頻繁請(qǐng)求,反復(fù)地在數(shù)據(jù)庫(kù)中進(jìn)行獲取是對(duì)時(shí)間和資源的浪費(fèi)。通過(guò)在findById(Integer id)方法上添加@Cacheable注解,如下面的程序清單所示,能夠確保將User對(duì)象保存在緩存users中,從而避免對(duì)數(shù)據(jù)庫(kù)的不必要訪問(wèn)。

@Cacheable(value="users")
public User findUserById(int id) {
    String sql="select * from t_user where id=?";
    return jdbcTemplate.queryForObject(sql, new UserRowMapper(), id);
}
class UserRowMapper implements RowMapper<User> {
    //rs為返回結(jié)果集,以每行為單位封裝著
    @Override
    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
        User user = new User();
        user.setID(rs.getInt("id"));
        user.setUserName(rs.getString("name"));
        user.setUserPwd(rs.getString("pwd"));
        return user;
    }
}

當(dāng)findUserById(int id)被調(diào)用時(shí),緩存切面會(huì)攔截調(diào)用并在緩存中查找之前以名users存儲(chǔ)的返回值。緩存的key是傳遞到findUserById(int id)方法中的id參數(shù)。如果按照這個(gè)key能夠找到值的話,就會(huì)返回找到的值,方法不會(huì)再被調(diào)用。如果沒有找到值的話,那么就會(huì)調(diào)用這個(gè)方法,并將返回值放到緩存之中,為下一次調(diào)用findUserById(int id)方法做好準(zhǔn)備。

當(dāng)@Cacheable為接口方法添加注解后,所有實(shí)現(xiàn)類都會(huì)應(yīng)用相同的緩存規(guī)則。

當(dāng)一個(gè)全新的User對(duì)象通過(guò)addUser(User user)方法保存之后,很可能馬上就會(huì)請(qǐng)求這條記錄。所以,當(dāng)save()方法調(diào)用后,立即將user塞到緩存之中是很有意義的,這樣當(dāng)其他人通過(guò)findUserById(int id)對(duì)其進(jìn)行查找時(shí),它就已經(jīng)準(zhǔn)備就緒了。為了實(shí)現(xiàn)這一點(diǎn),可以在addUser(User user)方法上添加@CachePut注解,如下所示:

@CachePut(value="users")
public void addUser(User user) {
    String sql = "insert into t_user values(?,?,?)";
    jdbcTemplate.update(sql, null,user.getUserName(),user.getUserPwd());
    return user;
}

 當(dāng)addUser(User user)方法被調(diào)用時(shí),它首先會(huì)做所有必要的事情來(lái)保存user對(duì)象,然后返回的user會(huì)被放到users緩存中。在這里只有一個(gè)問(wèn)題:緩存的key。如前文所述,默認(rèn)的緩存key要基于方法的參數(shù)來(lái)確定。因?yàn)閍ddUser(User user)方法的唯一參數(shù)就是user,所以它會(huì)用作緩存的key。將users放在緩存中,而它的緩存key恰好是同一個(gè)user,這是不是有一點(diǎn)詭異呢?顯然,在這個(gè)場(chǎng)景中,默認(rèn)的緩存key并不是我們想要的。我們需要的緩存key是新保存user的ID,而不是user本身。所以,在這里需要指定一個(gè)key而不是使用默認(rèn)的key。讓我們看一下怎樣自定義緩存key。

自定義緩存key

@Cacheable和@CachePut都有一個(gè)名為key屬性,這個(gè)屬性能夠替換默認(rèn)的key,它是通過(guò)一個(gè)SpEL表達(dá)式計(jì)算得到的。任意的SpEL表達(dá)式都是可行的,但是更常見的場(chǎng)景是所定義的表達(dá)式與存儲(chǔ)在緩存中的值有關(guān),據(jù)此計(jì)算得到key。

具體到我們這個(gè)場(chǎng)景,我們需要將key設(shè)置為所保存user的ID。以參數(shù)形式傳遞給addUser(User user)的user還沒有保存,因此并沒有ID。我們只能通過(guò)addUser(User user)返回的user得到id屬性。

幸好,在為緩存編寫SpEL表達(dá)式的時(shí)候,Spring暴露了一些很有用的元數(shù)據(jù)。下表列出了SpEL中可用的緩存元數(shù)據(jù)。

對(duì)于addUser(User user)方法來(lái)說(shuō),我們需要的鍵是所返回user對(duì)象的id屬性。表達(dá)式#result能夠得到返回的user。借助這個(gè)對(duì)象,我們可以通過(guò)將key屬性設(shè)置為#result.id來(lái)引用id屬性:

@CachePut(value="users",key="#result.id")
  public void addUser(User user) {
        String sql = "insert into t_user values(?,?,?)";
        jdbcTemplate.update(sql, null,user.getUserName(),user.getUserPwd());
        return user;
    }

 按照這種方式配置@CachePut,緩存不會(huì)去干涉addUser(User user)方法的執(zhí)行,但是返回的user將會(huì)保存在緩存中,并且緩存的key與user的id屬性相同。

條件化緩存

通過(guò)為方法添加Spring的緩存注解,Spring就會(huì)圍繞著這個(gè)方法創(chuàng)建一個(gè)緩存切面。但是,在有些場(chǎng)景下我們可能希望將緩存功能關(guān)閉。

@Cacheable和@CachePut提供了兩個(gè)屬性用以實(shí)現(xiàn)條件化緩存:unless和condition,這兩個(gè)屬性都接受一個(gè)SpEL表達(dá)式。如果unless屬性的SpEL表達(dá)式計(jì)算結(jié)果為true,那么緩存方法返回的數(shù)據(jù)就不會(huì)放到緩存中。與之類似,如果condition屬性的SpEL表達(dá)式計(jì)算結(jié)果為false,那么對(duì)于這個(gè)方法緩存就會(huì)被禁用掉。

表面上來(lái)看,unless和condition屬性做的是相同的事情。但是,這里有一點(diǎn)細(xì)微的差別。unless屬性只能阻止將對(duì)象放進(jìn)緩存,但是在這個(gè)方法調(diào)用的時(shí)候,依然會(huì)去緩存中進(jìn)行查找,如果找到了匹配的值,就會(huì)返回找到的值。與之不同,如果condition的表達(dá)式計(jì)算結(jié)果為false,那么在這個(gè)方法調(diào)用的過(guò)程中,緩存是被禁用的。就是說(shuō),不會(huì)去緩存進(jìn)行查找,同時(shí)返回值也不會(huì)放進(jìn)緩存中。

移除緩存條目

@CacheEvict并不會(huì)往緩存中添加任何東西。相反,如果帶有@CacheEvict注解的方法被調(diào)用的話,那么會(huì)有一個(gè)或更多的條目會(huì)在緩存中移除。

那么在什么場(chǎng)景下需要從緩存中移除內(nèi)容呢?當(dāng)緩存值不再合法時(shí),我們應(yīng)該確保將其從緩存中移除,這樣的話,后續(xù)的緩存命中就不會(huì)返回舊的或者已經(jīng)不存在的值,其中一個(gè)這樣的場(chǎng)景就是數(shù)據(jù)被刪除掉了。這樣的話,UserDao的deleteUser(int id)方法就是使用@CacheEvict的絕佳選擇:

@CacheEvict(value="users")
public void deleteUser(int id) {
    String sql = "delete from t_user where id = ?";
    jdbcTemplate.update(sql, id);
}

 注意:與@Cacheable和@CachePut不同,@CacheEvict能夠應(yīng)用在返回值為void的方法上,而@Cacheable和@CachePut需要非void的返回值,它將會(huì)作為放在緩存中的條目。因?yàn)锧CacheEvict只是將條目從緩存中移除,因此它可以放在任意的方法上,甚至void方法。

從上述代碼可以看到,當(dāng)deleteUser()調(diào)用時(shí),會(huì)從緩存中刪除一個(gè)條目。被刪除條目的key與傳遞進(jìn)來(lái)的id參數(shù)的值相等。

@CacheEvict有多個(gè)屬性,如下表所示,這些屬性會(huì)影響到該注解的行為,使其不同于默認(rèn)的做法??梢钥吹?,@CacheEvict的一些屬性與@Cacheable和@CachePut是相同的,另外還有幾個(gè)新的屬性。與@Cacheable和@CachePut不同,@CacheEvict并沒有提供unless屬性。

使用XML聲明緩存

Spring的cache命名空間提供了使用XML聲明緩存規(guī)則的方法,可以作為面向注解緩存的替代方案。因?yàn)榫彺媸且环N面向切面的行為,所以cache命名空間會(huì)與Spring的aop命名空間結(jié)合起來(lái)使用,用來(lái)聲明緩存所應(yīng)用的切點(diǎn)在哪里。

要開始配置XML聲明的緩存,首先需要?jiǎng)?chuàng)建Spring配置文件,這個(gè)文件中要包含cache和aop命名空間。cache命名空間定義了在Spring XML配置文件中聲明緩存的配置元素。如下表所示:

<!--將緩存通知綁定到切點(diǎn)上-->
<aop:config>
    <aop:advisor advice-ref="cacheAdvice" pointcut="execution(* com.boss.spring.learning.dao.*(..))"/>
</aop:config>
<cache:advice id="cacheAdvice">
    <cache:caching>
        <cache:cacheable cache="users" method="addUser"></cache:cacheable>
        <cache:cache-put cache="users" method="addUser" key="#result.id"></cache:cache-put>
        <cache:cache-evict cache="users" method="deleteUser"></cache:cache-evict>
    </cache:caching>
</cache:advice>
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
    <property name="caches">
        <set>
            <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="users"/>
        </set>
    </property>
</bean>

到此這篇關(guān)于詳解Spring數(shù)據(jù)緩存注解@Cacheable、@CachePut、@CacheEvict的文章就介紹到這了,更多相關(guān)Spring數(shù)據(jù)緩存注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • spring boot實(shí)戰(zhàn)之本地jar包引用示例

    spring boot實(shí)戰(zhàn)之本地jar包引用示例

    本篇文章主要介紹了spring boot實(shí)戰(zhàn)之本地jar包引用示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • 在IDEA里gradle配置和使用的方法步驟

    在IDEA里gradle配置和使用的方法步驟

    這篇文章主要介紹了在IDEA里gradle配置和使用的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Mybatis查詢記錄條數(shù)的實(shí)例代碼

    Mybatis查詢記錄條數(shù)的實(shí)例代碼

    這篇文章主要介紹了Mybatis查詢記錄條數(shù)的實(shí)例代碼,需要的朋友可以參考下
    2017-08-08
  • java實(shí)用驗(yàn)證碼的實(shí)現(xiàn)代碼

    java實(shí)用驗(yàn)證碼的實(shí)現(xiàn)代碼

    這篇文章主要為大家介紹了java實(shí)用驗(yàn)證碼的實(shí)現(xiàn)代碼,驗(yàn)證碼實(shí)際上就是隨機(jī)選擇一些字符以圖片的形式展現(xiàn)在頁(yè)面上,感興趣的小伙伴們可以參考一下
    2016-03-03
  • Java Map排序如何按照值按照鍵排序

    Java Map排序如何按照值按照鍵排序

    該文章主要介紹Java中三種Map(HashMap、LinkedHashMap、TreeMap)的默認(rèn)排序行為及實(shí)現(xiàn)按鍵排序和按值排序的方法,每種方法結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • 基于MyBatis的關(guān)聯(lián)查詢優(yōu)化與應(yīng)用實(shí)踐

    基于MyBatis的關(guān)聯(lián)查詢優(yōu)化與應(yīng)用實(shí)踐

    在實(shí)際項(xiàng)目開發(fā)中,關(guān)聯(lián)查詢是一種常見的需求,尤其是當(dāng)涉及到多個(gè)表之間的數(shù)據(jù)統(tǒng)計(jì)、關(guān)聯(lián)查詢以及嵌套對(duì)象的構(gòu)建時(shí),如何確保數(shù)據(jù)的準(zhǔn)確性和實(shí)時(shí)性,是開發(fā)者必須面對(duì)的挑戰(zhàn),本文將介紹基于MyBatis的關(guān)聯(lián)查詢優(yōu)化與應(yīng)用實(shí)踐,需要的朋友可以參考下
    2024-12-12
  • Java本地方法(JNA)詳解及常見問(wèn)題

    Java本地方法(JNA)詳解及常見問(wèn)題

    JNA(Java?Native?Access)是一個(gè)開源Java框架,用于無(wú)需編寫JNI代碼即可動(dòng)態(tài)訪問(wèn)本地系統(tǒng)庫(kù)如Windows的dll,它允許Java程序直接調(diào)用本地方法,這篇文章主要介紹了Java本地方法(JNA)詳解及常見問(wèn)題,需要的朋友可以參考下
    2024-09-09
  • SpringMVC注解的入門實(shí)例詳解

    SpringMVC注解的入門實(shí)例詳解

    這篇文章主要為大家介紹了SpringMVC注解的入門實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-01-01
  • 詳細(xì)解讀Java?Spring?AOP

    詳細(xì)解讀Java?Spring?AOP

    這篇文章主要介紹了Java?Spring框架中AOP的工作原理,AOP面向切面編程其實(shí)也可以被看作是一個(gè)設(shè)計(jì)模式去規(guī)范項(xiàng)目的結(jié)構(gòu)。需要的朋友可以收藏下,方便下次瀏覽觀看
    2021-12-12
  • Java由淺入深通關(guān)抽象類與接口下

    Java由淺入深通關(guān)抽象類與接口下

    在類中沒有包含足夠的信息來(lái)描繪一個(gè)具體的對(duì)象,這樣的類稱為抽象類,接口是Java中最重要的概念之一,它可以被理解為一種特殊的類,不同的是接口的成員沒有執(zhí)行體,是由全局常量和公共的抽象方法所組成,本文給大家介紹Java抽象類和接口,感興趣的朋友一起看看吧
    2022-04-04

最新評(píng)論

城固县| 玉龙| 上犹县| 柏乡县| 永顺县| 潼南县| 吐鲁番市| 淮北市| 岢岚县| 长春市| 巨野县| 乾安县| 普宁市| 同仁县| 昭苏县| 吴江市| 渑池县| 肃南| 库车县| 政和县| 锡林浩特市| 巩义市| 迁安市| 印江| 塘沽区| 陵水| 永泰县| 邯郸市| 资阳市| 隆回县| 通渭县| 嫩江县| 临朐县| 花莲市| 兴安县| 论坛| 翁源县| 安国市| 平遥县| 延寿县| 逊克县|