Spring?緩存在項目中的使用詳解
在上文介紹了 JSR-107 規(guī)范 后, 本文來介紹一下 Spring 緩存機(jī)制相關(guān)內(nèi)容。
1.Spring 緩存機(jī)制介紹
Spring 從 3.1開始,針對緩存定義了org.springframework.cache.Cache
和org.springframework.cache.CacheManager
接口,來統(tǒng)一不同的緩存技術(shù)。
并支持使用 JCache(JSR-107規(guī)范)注解來簡化項目的開發(fā)。
Spring 的緩存機(jī)制非常靈活,可以對容器中任意 Bean 或者 Bean 的方法進(jìn)行緩存,因此這種緩存機(jī)制可以在 JavaEE 應(yīng)用的任何層次上進(jìn)行緩存。在緩存的具體實現(xiàn)上,Spring 緩存底層也是借助其他緩存工具來實現(xiàn)的,例如 EhCache(Hibernate緩存工具),上層則以統(tǒng)一 API 編程。
Spring 緩存機(jī)制,Cache接口
為緩存的組件規(guī)范定義,包擴(kuò)緩存的各種操作 (添加緩存、刪除緩存、修改緩存等) 。在 Cache 接口下,Spring 為其提供了各種 xxxCache 的實現(xiàn)。如:RedisCache
、EhCacheCache
、ConcurrentMapCache
等;
2.Spring 緩存用到的概念
Ⅰ.兩個接口
Cache
:緩存接口,用來定義緩存的各種操作。Spring提供的具體實現(xiàn)有:RedisCache、EhCacheCache、ConcurrentMapCache等;CacheManager
:緩存管理器,管理各種緩存(Cache)組件
Ⅱ.三個注解(方法層次)
@Cacheable
:標(biāo)注在方法上,能夠根據(jù)方法的請求參數(shù)等對其結(jié)果進(jìn)行緩存。代表一個方法能被緩存@CacheEvict
:清空緩存(標(biāo)注在刪除方法上,用來清空緩存)@CachePut
:更新緩存。保證方法被調(diào)用,同時更新后的結(jié)果被緩存。
Ⅲ.一個注解(功能層次)
@EnableCaching
:開啟基于注解的緩存(想要使用緩存,就需要開啟緩存注解) Ⅳ.兩個自定義keyGenerator
:緩存數(shù)據(jù)時key生成策略serialize
:緩存數(shù)據(jù)時 value 值序列化策略
3.工作原理
每次調(diào)用需要緩存功能的方法時,Spring 都會檢查指定參數(shù)的指定的目標(biāo)方法是否已經(jīng)被調(diào)用過;如果有就直接從緩存中獲取方法調(diào)用后的結(jié)果,如果沒有就調(diào)用方法并緩存結(jié)果后返回給用戶。下次調(diào)用直接從緩存中獲取。
4.緩存在項目中的使用
我們來準(zhǔn)備一個環(huán)境,使用 Spring Boot + MyBatis 框架,來展示一下緩存在項目中的使用。此處就不啰嗦環(huán)境的搭建過程了,直接來介紹 Cache 緩存在項目中的使用。如需項目demo,請?zhí)D(zhuǎn)至文末代碼部分。
Ⅰ.使用@EnableCaching 開啟基于注解的緩存
@SpringBootApplication @MapperScan("com.example.cache.mapper") @EnableCaching //開啟基于注解的緩存 public class CacheApplication { public static void main(String[] args) { SpringApplication.run(CacheApplication.class, args); } }
Ⅱ.來個Controller
提示:此處的3個方法分別對應(yīng) @Cacheable、@CachePut、@CacheEvict 三個注解,接下來一一測試
@RestController public class UserController { @Autowired UserService userService; /** * 根據(jù)id獲取用戶信息(主要針對 @Cacheable 注解介紹) */ @GetMapping("/user/{id}") public User user(@PathVariable("id") Integer id){ User user = userService.getUser(id); return user; } /** * 更新用戶信息(主要針對 @CachePut 注解介紹) */ @PutMapping("/user") public User updateUser(User user) { User upUser = userService.updateUser(user); return upUser; } /** * 根據(jù)id刪除用戶數(shù)據(jù)(主要針對 @CacheEvict 注解介紹) */ @DeleteMapping("/user/{id}") public void deleteUser(@PathVariable("id") Integer id) { userService.deleteUser(id); } }
Ⅲ.在需要緩存的方法上,添加@Cacheable注解,表示該方法需要被緩存
public interface UserService { /** * 根據(jù)ID獲取用戶信息 * 此處 value 為 @Cacheable 屬性,該注解還有很多屬性,在 https://blog.csdn.net/lzb348110175/article/details/105349109 會有介紹,此處不做介紹 * 緩存相關(guān)注解,也可以寫到具體Service實現(xiàn)類上,此處寫在了接口上 */ @Cacheable(value = "user"/*,key="#id"*/) User getUser(Integer id); /** * 更新用戶信息 */ @CachePut(value = "user",key = "#user.id") User updateUser(User user); /** * 根據(jù)ID刪除用戶 */ @CacheEvict(value = "user", key = "#id") void deleteUser(Integer id); }
Ⅳ.getUser()方法實現(xiàn)
@Service @Slf4j public class UserServiceImpl implements UserService { @Autowired UserMapper userMapper; /** * 根據(jù)ID獲取用戶信息 */ @Override public User getUser(Integer id) { log.info("用戶"+id+"開始執(zhí)行數(shù)據(jù)庫查詢"); return userMapper.getUser(id); } /** * 更新用戶信息 */ @Override public User updateUser(User user) { log.info("開始更新用戶"+user.getId()+"的數(shù)據(jù)信息"); userMapper.updateUser(user); return user; } /** * 刪除用戶(此處僅演示刪除緩存數(shù)據(jù),實際數(shù)據(jù)庫數(shù)據(jù)不刪除,方便演示) */ @Override public void deleteUser(Integer id) { System.out.println("執(zhí)行刪除緩存數(shù)據(jù)操作"); } }
Ⅴ.測試@Cacheable緩存配置是否生效
- 第一步:分別調(diào)用
http://localhost:8080/user/1
和http://localhost:8080/user/2
請求,第一次請求時會調(diào)用數(shù)據(jù)庫查詢。 - 第二步:當(dāng)再次發(fā)送相同請求時,由于緩存中數(shù)據(jù)已經(jīng)存在,所以會通過緩存來獲取數(shù)據(jù)而不去讀取數(shù)據(jù)庫。
@Cacheable注解共有9個屬性可配置,這些屬性的配置可參考:@Cacheable注解屬性介紹。
@Cacheable注解相關(guān)屬性介紹
@Cacheable 注解提供的屬性,如何配置可參考:@Cacheable注解屬性介紹。
Ⅵ.測試@CachePut 是否會更新緩存
- 第一步:我們來調(diào)用
http://localhost:8080/user/1
接口,該接口首先會將返回的數(shù)據(jù)存入緩存。 - 第二步:我們來調(diào)用
http://localhost:8080/user
接口來更新id=1
的用戶。 - 第三步:再發(fā)送第一步中相同請求時,便會通過緩存來獲取數(shù)據(jù)而不去讀取數(shù)據(jù)庫,此時返回的內(nèi)容是已經(jīng)更新后的數(shù)據(jù)。
測試結(jié)果如下:第一次請求,查詢數(shù)據(jù)庫返回 Mary
;第二次請求,更新數(shù)據(jù)為Clark
;第三次再次發(fā)送查詢請求,在更新數(shù)據(jù)時緩存會同時被更改,由于緩存存在,所以不會調(diào)用數(shù)據(jù)庫請求,返回的是修改后的緩存中的數(shù)據(jù)Clark
。(切記:更新緩存時的 key 要與已經(jīng)存在緩存中的數(shù)據(jù) key 相同,否則緩存不會被更新。)
@CachePut 注解相關(guān)屬性介紹
@CachePut 注解提供的屬性,如何配置可參考:@Cacheable注解屬性介紹。(此處附的參考文章是正確的,我沒有附錯,因為它們配置都是一樣紫的)
Ⅶ.測試@CacheEvict 是否會刪除緩存
- 第一步:我們來調(diào)用
http://localhost:8080/user/1
接口,該接口首先會將返回的數(shù)據(jù)存入緩存。 - 第二步:繼續(xù)調(diào)用該接口,便會從緩存來獲取數(shù)據(jù)。
- 第三步:調(diào)用
http://localhost:8080/user/1
(發(fā)送的是 Delete 請求)執(zhí)行緩存刪除操作。 - 第四步:繼續(xù)發(fā)送第一步請求操作,由于緩存已經(jīng)被刪除,所以當(dāng)前請求操作會再次去數(shù)據(jù)庫查詢。
@CacheEvict 注解相關(guān)屬性介紹
@CacheEvict 注解提供的屬性,如何配置可參考:@Cacheable注解屬性介紹。(此處附的參考文章是正確的,我沒有附錯,因為它們配置都是一樣紫的)(切記:刪除緩存時的 key 要與已經(jīng)存在緩存中的數(shù)據(jù) key 相同,否則緩存不會被刪除。)除此之外,@CacheEvict 注解還提供了額外兩個屬性:allEntries
、beforeInvocation
。這兩個屬性如何使用,介紹如下:
allEntries
:清除指定緩存中的所有數(shù)據(jù),默認(rèn)為 false;(使用該屬性就不需要使用 key 屬性了)-
allEntries = false,默認(rèn)代表清除這個緩存中指定 key 的數(shù)據(jù)。
-
allEntries = true,指定清除這個緩存中所有的數(shù)據(jù)。
beforeInvocation
:清除緩存的操作是否在方法之前執(zhí)行,默認(rèn)為false;-
beforeInvocation = false,默認(rèn)代表緩存清除操作是在方法執(zhí)行之后執(zhí)行;如果出現(xiàn)異常緩存就不會清除。
beforeInvocation = true,代表清除緩存操作是在方法運行之前執(zhí)行,無論方法是否出現(xiàn)異常,緩存都清除。
Ⅷ.(了解)@Caching注解—應(yīng)用于復(fù)雜緩存規(guī)則的指定
//可以使用@Caching 來解決滿足項目開發(fā)的復(fù)雜緩存規(guī)則 @Caching( cacheable = { @Cacheable(value = "user",key = "#name") }, put = { @CachePut(value = "user",key = "#result.id"), @CachePut(value = "user",key = "#result.email") }, evict = { @CacheEvict(value = "user",key = "#name") } ) User getUserByName(String name);
Ⅸ.(了解)@CacheConfig注解—應(yīng)用于抽取當(dāng)前類下緩存使用的公共配置
比如 UserService 類下的所有操作,①緩存都是存在 key = “user” 下,②使用的 keyGenerator 都是我們自定義的,那么我們可以使用 @CacheConfig 注解來抽取緩存的公共配置,并將該注解標(biāo)注在該 UserService類上即可。
(公共配置支持:cacheNames
、keyGenerator
、cacheManager
、cacheResolver
4個屬性的配置)
@CacheConfig(cacheNames="emp",cacheManager = "employeeCacheManager",keyGenerator = "myKeyGenerator",cacheResolver = "myCacheResolver") //抽取緩存的公共配置 public interface UserService{ //代碼省略 }
5.附上demo
Spring cache 緩存使用demo
百度網(wǎng)盤下載地址:
鏈接: https://pan.baidu.com/s/1nxUOTAuQIHsiQRD7Bifi5w
提取碼: 2jyz
到此這篇關(guān)于Spring 緩存在項目中的使用的文章就介紹到這了,更多相關(guān)Spring 緩存在項目使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入理解SpringBoot中關(guān)于Mybatis使用方法
這篇文章主要介紹了SpringBoot中關(guān)于Mybatis使用方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-03-03Spark調(diào)優(yōu)多線程并行處理任務(wù)實現(xiàn)方式
這篇文章主要介紹了Spark調(diào)優(yōu)多線程并行處理任務(wù)實現(xiàn)方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-08-08Java中的ReadWriteLock高效處理并發(fā)讀寫操作實例探究
這篇文章主要為大家介紹了Java中的ReadWriteLock高效處理并發(fā)讀寫操作實例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01springMVC在restful風(fēng)格的性能優(yōu)化方案
這篇文章主要介紹了springMVC在restful風(fēng)格的性能優(yōu)化方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08詳解Java8新特性Stream之list轉(zhuǎn)map及問題解決
這篇文章主要介紹了詳解Java8新特性Stream之list轉(zhuǎn)map及問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09SpringBoot+jsp項目啟動出現(xiàn)404的解決方法
這篇文章主要介紹了SpringBoot+jsp項目啟動出現(xiàn)404的解決方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03spring boot springjpa 支持多個數(shù)據(jù)源的實例代碼
這篇文章主要介紹了spring boot springjpa 支持多個數(shù)據(jù)源的實例代碼,需要的朋友可以參考下2018-04-04