SpringBoot結(jié)合Redis實(shí)現(xiàn)緩存管理功能
一、概述
目標(biāo):
- 熟悉Spring Cache基礎(chǔ)組件及作用
- 熟悉Spring Cache常用注解及作用
- 掌握SpringBoot結(jié)合Redis實(shí)現(xiàn)緩存管理
二、 Spring Cache基礎(chǔ)組件
keyGenerator
keyGenerator
是用于生成緩存鍵(Cache Key)的組件。緩存鍵是用于在緩存中唯一標(biāo)識(shí)緩存數(shù)據(jù)的值。默認(rèn)情況下,Spring Cache 使用參數(shù)列表作為緩存鍵。但在某些情況下,如果需要自定義緩存鍵的生成邏輯,則可以創(chuàng)建自定義的KeyGenerator
實(shí)現(xiàn)并配置到 Spring 中,如果沒(méi)有自定義的話Spring提供默認(rèn)的keyGenerator
——SimplekeyGenerator
,它會(huì)根據(jù)方法參數(shù)列表生成一個(gè)唯一的緩存 key。cacheManager
在 Spring Cache 框架中,
CacheManager
是用于管理緩存實(shí)例的組件。它可以創(chuàng)建和管理多個(gè)緩存,每個(gè)緩存都有一個(gè)唯一的名稱。當(dāng)開(kāi)發(fā)者在項(xiàng)目中配置了 Redis(或其他支持的緩存中間件),Spring 會(huì)自動(dòng)使用相應(yīng)的CacheManager
實(shí)現(xiàn),如RedisCacheManager
。 如果沒(méi)有配置任何緩存中間件,Spring 默認(rèn)會(huì)采用SimpleCacheManager
作為緩存管理器。SimpleCacheManager
內(nèi)部使用ConcurrentHashMap
來(lái)維護(hù)緩存數(shù)據(jù),它是一個(gè)線程安全的 HashMap 實(shí)現(xiàn)。這種情況下,并不需要額外的緩存中間件,Spring 會(huì)將緩存數(shù)據(jù)存儲(chǔ)在內(nèi)存中。cacheResolver 和cacheManager作用一樣,使用時(shí)二選一
三、 緩存管理注解
@EnableCaching
該注解用于啟用 Spring Framework 的緩存支持。通常在配置類上使用,表示開(kāi)啟緩存機(jī)制。有一個(gè)可選參數(shù) proxyTargetClass,默認(rèn)值為 false,表示使用 JDK 動(dòng)態(tài)代理實(shí)現(xiàn) AOP,如果設(shè)置為 true,則表示使用 CGLIB 代理進(jìn)行 AOP。
@CacheConfig
@CacheConfig 注解用于配置緩存的公共屬性,如緩存名稱、緩存管理器等??梢栽陬惣?jí)別上使用,表示該類中的所有方法都具有相同的緩存規(guī)則。 該注解可選參數(shù):
- cacheNames:指定緩存名稱。
- keyGenerator:指定緩存 key 生成策略。
- cacheManager:指定緩存管理器。
@CacheAble
@Cacheable
注解用于標(biāo)注方法的返回值可以被緩存,通常用于查詢操作。如果緩存中存在對(duì)應(yīng)的數(shù)據(jù),則直接從緩存中獲取數(shù)據(jù)返回,否則執(zhí)行方法并將返回值存入緩存中。該注解可選參數(shù):cacheNames:指定緩存名稱。
key:指定緩存 key,需要使用 SpEL 表達(dá)式進(jìn)行動(dòng)態(tài)計(jì)算,沒(méi)有指定的話,會(huì)使用
keyGenerator
。cacheName
和key
可以組合成最終用于在 Redis 等緩存中存儲(chǔ)數(shù)據(jù)的 key。通常情況下,cacheName
代表緩存的名稱,而key
則用于標(biāo)識(shí)緩存中的具體數(shù)據(jù)。當(dāng)使用@Cacheable(cacheNames = "myCache", key = "#user.id")
這樣的注解時(shí),Spring 將會(huì)根據(jù)給定的cacheName
和key
生成一個(gè)唯一的緩存 key,然后將方法返回的數(shù)據(jù)緩存到 Redis 中。- 例如,在 Redis 中可能會(huì)生成類似于
myCache::123
這樣的鍵來(lái)存儲(chǔ)緩存數(shù)據(jù),其中myCache
是緩存名稱,123
則是根據(jù)#user.id
表達(dá)式計(jì)算得出的具體鍵值。
condition:指定一個(gè) SpEL 表達(dá)式,當(dāng)條件為 true 時(shí)才會(huì)進(jìn)行緩存操作。
unless:指定一個(gè) SpEL 表達(dá)式,當(dāng)條件為 false 時(shí)才會(huì)進(jìn)行緩存操作。
condition
屬性是在方法執(zhí)行前計(jì)算的,因此無(wú)法獲取到方法返回結(jié)果。unless
屬性是在方法執(zhí)行后計(jì)算的,因此可以拿到方法返回結(jié)果,即SpEL 表達(dá)式中可以使用#result獲取到方法返回值。
sync:指定緩存是否需要同步更新。默認(rèn)情況下,Spring Cache 不會(huì)對(duì)緩存進(jìn)行同步更新,即在多線程環(huán)境下可能會(huì)出現(xiàn)緩存不一致的問(wèn)題。但是,如果我們希望在緩存更新時(shí)進(jìn)行同步操作,可以使用
sync
屬性來(lái)實(shí)現(xiàn)。
//當(dāng)方法被多個(gè)線程并發(fā)調(diào)用時(shí),只有一個(gè)線程能夠執(zhí)行方法并更新緩存,其他線程會(huì)被阻塞,直到更新完成后才能繼續(xù)執(zhí)行。 @Cacheable(cacheNames = "myCache", key = "#id", sync = true) public User getUserById(Long id) { //.... } //注意:使用 `sync` 屬性會(huì)增加緩存訪問(wèn)的時(shí)間和資源消耗,因此建議只在必要的情況下使用。另外,對(duì)于高并發(fā)場(chǎng)景,使用 `sync` 屬性可能會(huì)導(dǎo)致性能問(wèn)題,因此需要謹(jǐn)慎使用。
以下是常用的 SpEL 表達(dá)式及其說(shuō)明:
表達(dá)式 說(shuō)明 #root 代表被調(diào)用方法的參數(shù)列表 #root.target 代表被調(diào)用方法的目標(biāo)對(duì)象 #root.caches 代表方法調(diào)用對(duì)應(yīng)的緩存 #root.methodName 代表被調(diào)用方法的名稱 #root.targetClass 代表被調(diào)用方法所在的類 #result 代表方法調(diào)用的返回結(jié)果(僅在 @Cacheable 和 @CachePut 注解中有效) #argument 代表方法的參數(shù),例如 #a0 代表第一個(gè)參數(shù),#p0 也代表第一個(gè)參數(shù) T(...) 調(diào)用靜態(tài)方法,比如 T(java.lang.Math).PI 方法調(diào)用 直接調(diào)用方法,比如 hasPermission('read') 集合訪問(wèn) 訪問(wèn)數(shù)組、列表、集合等元素,比如 list[0] 屬性訪問(wèn) 訪問(wèn)對(duì)象的屬性,比如 [user.name] @CachePut
@CachePut 注解用于緩存標(biāo)注方法的返回值,不管緩存中是否存在相同的鍵值,通常用于增加或更新操作。在方法執(zhí)行后,將執(zhí)行結(jié)果緩存到指定的緩存中。
該注解可選參數(shù):
- cacheNames:同
@Cacheable
。 - key:同
@Cacheable
。 - condition: 同
@Cacheable
。 - unless:同
@Cacheable
。
- cacheNames:同
@CacheEvict
@CacheEvict 注解用于標(biāo)注方法執(zhí)行后刪除緩存中的數(shù)據(jù),通常用于刪除操作。
該注解可選參數(shù):
- cacheNames:同
@Cacheable
。 - key:同
@Cacheable
。 - condition:同
@Cacheable
。 - allEntries:配合
cacheNames
一起使用,當(dāng)allEntries
屬性設(shè)置為true
時(shí),表示清除緩存中緩存名稱為cacheNames
的所有條目。allEntries
默認(rèn)值為false
,表示只刪除與該方法對(duì)應(yīng)的緩存條目。- 例如:@CacheEvict(cacheNames = "k1",allEntries = true),會(huì)刪除緩存中所有緩存名稱為k1的鍵值對(duì)。
- beforeInvocation:當(dāng)
beforeInvocation
屬性設(shè)置為true
時(shí),表示在方法執(zhí)行之前清除緩存;即使方法執(zhí)行出現(xiàn)異常,緩存仍然會(huì)被清除。當(dāng)beforeInvocation
屬性設(shè)置為false
(默認(rèn)值)時(shí),表示在方法執(zhí)行之后清除緩存;如果方法執(zhí)行出現(xiàn)異常,緩存不會(huì)被清除。
- cacheNames:同
四、 代碼示例
添加pom依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
數(shù)據(jù)緩存
@Service @CacheConfig(cacheNames = "user") public class CacheService { @CachePut(key = "'userId:' + #p0.userId") public User addUser(User user){ System.out.println("添加成功:user = " + user); return user; } @Cacheable(key = "'userId:' + #p0") public User getUser(Integer userId){ User userFromDB = getUserFromDB(userId); System.out.println("查詢成功: userId = " + userId); return userFromDB; } @CachePut(key = "'userId:' + #p0") public User update(Integer userId,User user){ updateUserInDB(userId,user); System.out.println("更新成功:userId = " + userId); return user; } private void updateUserInDB(Integer userId,User user) { user.setUsername("DB_user"); } private User getUserFromDB(Integer userId) { User user = new User(); user.setUserId(userId); user.setUsername("DB_user"); return user; } @CacheEvict(cacheNames = "k1",allEntries = true) public void del(int id){ } }
單元測(cè)試
@SpringBootTest public class CacheServiceTest { @Resource private CacheService cacheService; private User user; @BeforeEach void initUser(){ user = new User(); user.setUserId(1); user.setUsername("zhang san"); user.setNickname("xiao san"); user.setPhone("18788888888"); } @Test void addCacheTest(){ cacheService.addUser(user); } @Test void getCacheTest(){ User user = cacheService.getUser(1); System.out.println("user = " + user); } @Test void updateCacheTest(){ cacheService.update(1,user); } @Test void delCacheTest(){ cacheService.del(2); } @Autowired private RedisTemplate redisTemplate; @Test public void key() { // 這里將緩存key都撈出來(lái) Set<String> keys = (Set<String>) redisTemplate.execute((RedisCallback<Set<String>>) connection -> { Set<byte[]> sets = connection.keys("k*".getBytes()); Set<String> ans = new HashSet<>(); assert sets != null; for (byte[] b : sets) { ans.add(new String(b)); } return ans; }); System.out.println("keys = " + keys); } }
總結(jié)
以上就是SpringBoot結(jié)合Redis實(shí)現(xiàn)緩存管理功能的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Redis緩存管理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- SpringBoot整合Redis實(shí)現(xiàn)token緩存
- SpringBoot整合redis使用緩存注解詳解
- SpringBoot+MyBatis+Redis實(shí)現(xiàn)分布式緩存
- springboot使用redis注解做緩存的基本操作方式
- SpringBoot中Redis的緩存更新策略詳解
- springboot整合ehcache和redis實(shí)現(xiàn)多級(jí)緩存實(shí)戰(zhàn)案例
- SpringBoot結(jié)合Redis實(shí)現(xiàn)緩存
- SpringBoot使用Redis實(shí)現(xiàn)分布式緩存
- SpringBoot中的Redis?緩存問(wèn)題及操作方法
- SpringBoot3.0集成Redis緩存的實(shí)現(xiàn)示例
相關(guān)文章
使用注解@Validated效驗(yàn)VO參數(shù)是否合規(guī)
這篇文章主要為大家介紹了使用注解@Validated效驗(yàn)VO參數(shù)是否合規(guī)過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05servlet實(shí)現(xiàn)文件下載的步驟及說(shuō)明詳解
這篇文章主要為大家詳細(xì)介紹了servlet實(shí)現(xiàn)文件下載的步驟及說(shuō)明,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09Spring Cloud Config與Bus整合實(shí)現(xiàn)微服務(wù)配置自動(dòng)刷新功能
通過(guò)整合SpringCloud Config與Spring Cloud Bus,實(shí)現(xiàn)了微服務(wù)配置的自動(dòng)刷新功能,這個(gè)機(jī)制允許一個(gè)微服務(wù)實(shí)例在配置更新時(shí)通過(guò)消息總線通知其他所有實(shí)例同步更新,從而保持配置的一致性并提升系統(tǒng)的運(yùn)維效率2024-10-10SpringBoot校園綜合管理系統(tǒng)實(shí)現(xiàn)流程分步講解
這篇文章主要介紹了SpringBoot+Vue實(shí)現(xiàn)校園綜合管理系統(tǒng)流程分步講解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-09-09Apache Commons Math3學(xué)習(xí)之?dāng)?shù)值積分實(shí)例代碼
這篇文章主要介紹了Apache Commons Math3學(xué)習(xí)之?dāng)?shù)值積分實(shí)例代碼,涉及使用辛普森積分的例子,這里分享給大家,供需要的朋友參考。2017-10-10SpringBoot如何基于POI-tl和word模板導(dǎo)出龐大的Word文件
這篇文章主要介紹了SpringBoot如何基于POI-tl和word模板導(dǎo)出龐大的Word文件,poi-tl是一個(gè)基于Apache?POI的Word模板引擎,也是一個(gè)免費(fèi)開(kāi)源的Java類庫(kù)2022-08-08