一、 SpringCache緩存介紹
Spring Cache是一個框架,實現了基於註解的緩存功能,只需要簡單地加一個註解,就能實現緩存功能,大大簡化我們在業務中操作緩存的代碼。
Spring Cache只是提供了一層抽象,底層可以切換不同的cache實現。具體就是通過CacheManager接口來統一不同的緩存技術。CacheManager是Spring提供的各種緩存技術抽象接口。
針對不同的緩存技術需要實現不同的CacheManager:
CacheManager 描述
EhCacheCacheManager 使用EhCache作為緩存技術
GuavaCacheManager 使用Google的GuavaCache作為緩存技術
RedisCacheManager 使用Redis作為緩存技術
二、 SpringCache註解
在SpringCache中提供了很多緩存操作的註解,常見的是以下的幾個:
註解 説明
@EnableCaching 開啓緩存註解功能
@Cacheable 在方法執行前spring先查看緩存中是否有數據,如果有數據,則直接返回緩存數據;若沒有數據,調用方法並將方法返回值放到緩存中
@CachePut 將方法的返回值放到緩存中
@CacheEvict 將一條或多條數據從緩存中刪除
2.1 @CachePut註解
@CachePut 説明:
作用: 將方法返回值,放入緩存
value: 緩存的名稱, 每個緩存名稱下面可以有很多key
key: 緩存的key ----------> 支持Spring的表達式語言SPEL語法
使用示例:在save方法上加註解@CachePut。當前UserController的save方法是用來保存用户信息的,我們希望在該用户信息保存到數據庫的同時,也往緩存中緩存一份數據,我們可以在save方法上加上註解 @CachePut,用法如下:
@CachePut(value = "userCache", key = "#user.id") @PostMapping public User save(User user){ userService.save(user); return user; }
key的寫法如下:
#user.id : #user指的是方法形參的名稱, id指的是user的id屬性 , 也就是使用user的id屬性作為key ;
#user.name: #user指的是方法形參的名稱, name指的是user的name屬性 ,也就是使用user的name屬性作為key ;
#result.id : #result代表方法返回值,該表達式 代表以返回對象的id屬性作為key ;
#result.name : #result代表方法返回值,該表達式 代表以返回對象的name屬性作為key ;
2.2 @CacheEvict註解
@CacheEvict 説明:
作用: 清理指定緩存
value: 緩存的名稱,每個緩存名稱下面可以有多個key
key: 緩存的key ----------> 支持Spring的表達式語言SPEL語法
使用示例: 在 delete 方法上加註解@CacheEvict。當我們在刪除數據庫user表的數據的時候,我們需要刪除緩存中對應的數據,此時就可以使用@CacheEvict註解, 具體的使用方式如下:
@CacheEvict(value = "userCache",key = "#p0") //#p0 代表第一個參數 //@CacheEvict(value = "userCache",key = "#id") //#id 代表變量名為id的參數 @DeleteMapping("/{id}") public void delete(@PathVariable Long id){ userService.removeById(id); }
2.3 @Cacheable註解
@Cacheable 説明:
作用: 在方法執行前,spring先查看緩存中是否有數據,如果有數據,則直接返回緩存數據;若沒有數據,調用方法並將方法返回值放到緩存中
value: 緩存的名稱,每個緩存名稱下面可以有多個key
key: 緩存的key ----------> 支持Spring的表達式語言SPEL語法
使用情況1:在getById上加註解@Cacheable
@Cacheable(value = "userCache",key = "#id") @GetMapping("/{id}") public User getById(@PathVariable Long id){ User user = userService.getById(id); return user; }
當我們在測試時,查詢一個數據庫不存在的id值,第一次查詢緩存中沒有,也會查詢數據庫。而第二次再查詢時,會發現,不再查詢數據庫了,而是直接返回,那也就是説如果根據ID沒有查詢到數據,那麼會自動緩存一個null值。
我們能不能做到,當查詢到的值不為null時,再進行緩存,如果為null,則不緩存呢? 答案是可以的。
使用情況2: 緩存非null值。
在@Cacheable註解中,提供了兩個屬性分別為: condition, unless 。
condition : 表示滿足條件時才緩存數據;
unless : 表示滿足條件則不緩存 ; 與上述的condition是反向的 ;
@Cacheable(value = "userCache",key = "#id", unless = "#result == null") @GetMapping("/{id}") public User getById(@PathVariable Long id){ User user = userService.getById(id); return user; }
注意: 此處,我們使用的時候只能夠使用 unless, 因為在condition中,我們是無法獲取到結果 #result的。
使用情況3: 在list方法上加註解@Cacheable。
在list方法中進行查詢時,有兩個查詢條件,如果傳遞了id,根據id查詢; 如果傳遞了name, 根據name查詢,那麼我們緩存的key在設計的時候,就需要既包含id,又包含name。 具體的代碼實現如下:
@Cacheable(value = "userCache",key = "#user.id + '_' + #user.name") @GetMapping("/list") public List<User> list(User user){ LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(user.getId() != null,User::getId,user.getId()); queryWrapper.eq(user.getName() != null,User::getName,user.getName()); List<User> list = userService.list(queryWrapper); return list; }