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