Spring緩存註解@Cacheable,@CachePut , @CacheEvict使用

@Cacheable

@Cacheable 的作用 主要針對方法配置,能夠根據方法的請求參數對其結果進行緩存
@Cacheable 作用和配置方法
在這裏插入圖片描述@Cacheable(value=”accountCache”),這個註釋的意思是,當調用這個方法的時候,會從一個名叫 accountCache 的緩存中查詢,如果沒有,則執行實際的方法(即查詢數據庫),並將執行的結果存入緩存中,否則返回緩存中的對象。這裏的緩存中的 key 就是參數 userName,value 就是 Account 對象。“accountCache”緩存是在 spring*.xml 中定義的名稱。

@Cacheable(value="accountCache")// 使用了一個緩存名叫 accountCache 
public Account getAccountByName(String userName) {
     // 方法內部實現不考慮緩存邏輯,直接實現業務
     System.out.println("real query account."+userName); 
     return getFromDB(userName); 
} 

@CachePut

@CachePut 的作用 主要針對方法配置,能夠根據方法的請求參數對其結果進行緩存,和 @Cacheable 不同的是,它每次都會觸發真實方法的調用
@CachePut 作用和配置方法
在這裏插入圖片描述實例

@CachePut 註釋,這個註釋可以確保方法被執行,同時方法的返回值也被記錄到緩存中,實現緩存與數據庫的同步更新。

@CachePut(value="accountCache",key="#account.getName()")// 更新accountCache 緩存
public Account updateAccount(Account account) { 
   return updateDB(account); 
} 

@CacheEvict

@CachEvict 的作用 主要針對方法配置,能夠根據一定的條件對緩存進行清空
@CacheEvict 作用和配置方法
在這裏插入圖片描述實例

@CacheEvict(value="accountCache",key="#account.getName()")// 清空accountCache 緩存  
public void updateAccount(Account account) {
     updateDB(account); 
} 

@CacheEvict(value="accountCache",allEntries=true)// 清空accountCache 緩存
public void reload() {
     reloadAll()
}

@Cacheable(value="accountCache",condition="#userName.length() <=4")// 緩存名叫 accountCache 
public Account getAccountByName(String userName) { 
 // 方法內部實現不考慮緩存邏輯,直接實現業務
 return getFromDB(userName); 
}

@CacheConfig

所有的@Cacheable()裏面都有一個value=“xxx”的屬性,這顯然如果方法多了,寫起來也是挺累的,如果可以一次性聲明完 那就省事了,
所以,有了@CacheConfig這個配置,@CacheConfig is a class-level annotation that allows to share the cache names,如果你在你的方法寫別的名字,那麼依然以方法的名字爲準。

  @CacheConfig("books")
    public class BookRepositoryImpl implements BookRepository {
    
        @Cacheable
        public Book findBook(ISBN isbn) {...}
    }

條件緩存

下面提供一些常用的條件緩存

//@Cacheable將在執行方法之前( #result還拿不到返回值)判斷condition,如果返回true,則查緩存; 
@Cacheable(value = "user", key = "#id", condition = "#id lt 10")
public User conditionFindById(final Long id)  

//@CachePut將在執行完方法後(#result就能拿到返回值了)判斷condition,如果返回true,則放入緩存; 
@CachePut(value = "user", key = "#id", condition = "#result.username ne 'zhang'")  
public User conditionSave(final User user)   

//@CachePut將在執行完方法後(#result就能拿到返回值了)判斷unless,如果返回false,則放入緩存;(即跟condition相反)
@CachePut(value = "user", key = "#user.id", unless = "#result.username eq 'zhang'")
public User conditionSave2(final User user)   

//@CacheEvict, beforeInvocation=false表示在方法執行之後調用(#result能拿到返回值了);且判斷condition,如果返回true,則移除緩存;
@CacheEvict(value = "user", key = "#user.id", beforeInvocation = false, condition = "#result.username ne 'zhang'")  
public User conditionDelete(final User user) 

@Caching

有時候我們可能組合多個Cache註解使用;比如用戶新增成功後,我們要添加id–>user;username—>user;email—>user的緩存;此時就需要@Caching組合多個註解標籤了。

@Caching(put = {
@CachePut(value = "user", key = "#user.id"),
@CachePut(value = "user", key = "#user.username"),
@CachePut(value = "user", key = "#user.email")
})
public User save(User user) {

自定義緩存註解

比如之前的那個@Caching組合,會讓方法上的註解顯得整個代碼比較亂,此時可以使用自定義註解把這些註解組合到一個註解中,如:

@Caching(put = {
@CachePut(value = "user", key = "#user.id"),
@CachePut(value = "user", key = "#user.username"),
@CachePut(value = "user", key = "#user.email")
})
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface UserSaveCache {
}

這樣我們在方法上使用如下代碼即可,整個代碼顯得比較乾淨。

@UserSaveCache
public User save(User user)

擴展

比如findByUsername時,不應該只放username–>user,應該連同id—>user和email—>user一起放入;這樣下次如果按照id查找直接從緩存中就命中了

@Caching(
    cacheable = {
       @Cacheable(value = "user", key = "#username")
    },
    put = {
       @CachePut(value = "user", key = "#result.id", condition = "#result != null"),
       @CachePut(value = "user", key = "#result.email", condition = "#result != null")
    }
)
public User findByUsername(final String username) {
    System.out.println("cache miss, invoke find by username, username:" + username);
    for (User user : users) {
        if (user.getUsername().equals(username)) {
            return user;
        }
    }
    return null;
}

其實對於:id—>user;username—->user;email—>user;更好的方式可能是:id—>user;username—>id;email—>id;保證user只存一份;如:

@CachePut(value="cacheName", key="#user.username", cacheValue="#user.username")  
public void save(User user)   


@Cacheable(value="cacheName", key="#user.username", cacheValue="#caches[0].get(#caches[0].get(#username).get())")  
public User findByUsername(String username)  

SpEL上下文數據

Spring Cache提供了一些供我們使用的SpEL上下文數據,下表直接摘自Spring官方文檔:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章