Redis和Caffeine的區別
相同點
- 兩個都是緩存的方式
不同點
- redis是分布式緩存,通過網絡將數據存儲到redis服務器內存里
- caffeine是將數據存儲在本地應用里
- caffeine和redis相比,沒有了網絡IO上的消耗
聯系
- 一般將兩者結合起來,形成一二級緩存。
- 使用流程大致如下:
- 先去一級緩存中查找數據(caffeine-本地應用內),
- 如果沒有的話,去二級緩存中查找數據(redis-內存),
- 再沒有,再去數據庫中查找數據(數據庫-磁盤)
Spring Boot 緩存 Caffeine使用
1.需要添加的依賴
1
2
3
4
5
6
7
8
9
|
< dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-cache</ artifactId > </ dependency > < dependency > < groupId >com.github.ben-manes.caffeine</ groupId > < artifactId >caffeine</ artifactId > < version >2.8.6</ version > </ dependency > |
2.配置
在SpringBoot中配置Caffeine,控制緩存行為(例如過期時間,緩存大小限制等)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import com.github.benmanes.caffeine.cache.Caffeine; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.caffeine.CaffeineCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.concurrent.TimeUnit; @Configuration @EnableCaching //開啟緩存 public class CaffeinConfig { @Bean //配置Caffeine緩存行為(例如到期,緩存大小限制等) public Caffeine caffeineConfig() { Caffeine caffeine = Caffeine.newBuilder() .expireAfterWrite( 60 , TimeUnit.MINUTES) .maximumSize( 1000 ); return caffeine; } @Bean public CacheManager cacheManager(Caffeine caffeine) { CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager(); caffeineCacheManager.setCaffeine(caffeine); return caffeineCacheManager; } } |
Caffeine配置說明:
initialCapacity=[integer]
:初始的緩存空間大小
maximumSize=[long]
:緩存的最大條數
maximumWeight=[long]
:緩存的最大權重
expireAfterAccess=[duration]
:最后一次寫入或訪問后經過固定時間過期
expireAfterWrite=[duration]
:最后一次寫入后經過固定時間過期
refreshAfterWrite=[duration]
:創建緩存或者最近一次更新緩存后經過固定的時間間隔,刷新緩存
recordStats
:開發統計功能
注意:
expireAfterWrite和expireAfterAccess同時存在時,以expireAfterWrite為準。
maximumSize和maximumWeight不可以同時使用
3.使用Caffeine緩存
示例1:
使用 @Cacheable(cacheNames = “xxx”) 或 @Cacheable(value = “xxx”) 注解在方法上。
1
2
3
4
5
|
@Cacheable (value = "caffeinSet_Value" ) public String caffeinSetValue(Integer number) { String str = number % 2 == 0 ? number + "是偶數" : number + "是奇數" ; return str; } |
說明: 每次執行方法 caffeinSetValue 時,會先去 caffeinSet_Value 緩存里根據傳入的 number 查找有沒有匹配的緩存,有則直接返回結果;沒有則執行方法,執行完后將結果加入緩存里,下次如果匹配直接返回。
示例2:
當有多個參數時,@Cacheable 注解里可以使用 key 來選擇參數進行判斷緩存是否存在。可以使用 condition 來進行條件篩選,只有滿足條件的才會加入緩存。
1
2
3
4
5
6
7
8
|
/** * number為偶數時才會緩存,緩存的key是傳入的number值 */ @Cacheable (value = "caffeinSet_Value" , key = "#number" , condition = "#number%2==0" ) public String caffeinSetValue(Integer number,String st) { String str = number % 2 == 0 ? number + "是偶數" : number + "是奇數" ; return str+st; } |
說明: 假如傳入的參數 number 是2,首先判斷 caffeinSet_Value 緩存里有沒有 key 是2的,有則直接回結果。沒有則執行方法,因為滿足 condition 的條件則最后將結果加入緩存。
假如傳入的參數 number 是奇數,則每次都會執行方法,因為不滿足 condition ,不會被加入緩存。
示例3:
1
2
3
4
5
|
@Cacheable (value = "caffeinSet_Value" , key = "#student.name" , condition = "#student.age>10" ) public Student caffeinSetValue(Student student,Integer number) { System.out.println( 11111 ); return student; } |
說明: 根據student對象里的name去caffeinSetValue緩存里查找。只有student對象里的age大于10的時候才會緩存結果。
注意:
一個方法A調同一個類里的另一個有緩存注解的方法B,這樣是不走緩存的。
例如在同一個CaffeinConsumer 類里面 invalidCache 調用 caffeinSetValue,是不走緩存的,緩存是不生效的;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Service public class CaffeinConsumer { public String invalidCache(Integer number,String st) { String str = caffeinSetValue(number,st); return str; } /** * number為偶數時才會緩存,緩存的key是傳入的number值 */ @Cacheable (value = "caffeinSet_Value" , key = "#number" , condition = "#number%2==0" ) public String caffeinSetValue(Integer number,String st) { String str = number % 2 == 0 ? number + "是偶數" : number + "是奇數" ; return str+st; } } |
解決方案:
1.不使用注解的方式,直接取 Ehcache 的 CacheManger 對象,把需要緩存的數據放到里面,類似于使用 Map,緩存的邏輯自己控制;或者可以使用redis的緩存方式去添加緩存;
2.把方法A和方法B放到兩個不同的類里面,例如:如果兩個方法都在同一個service接口里,把方法B放到另一個service里面,這樣在A方法里調B方法,就可以使用B方法的緩存。
Caffeine其他常用注解
1.@CachePut:
被@CachePut標注的方法在執行前不會去檢查緩存中是否存在之前執行過的結果,而是每次都會執行該方法,并將執行結果以鍵值對的形式存入指定的緩存中。
2.@CacheEvict:
@CacheEvict是用來標注在需要清除緩存元素的方法或類上的。當標記在一個類上時表示其中所有的方法的執行都會觸發緩存的清除操作。
@CacheEvict可以指定的屬性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的語義與@Cacheable對應的屬性類似。
即value表示清除操作是發生在哪些Cache上的(對應Cache的名稱);key表示需要清除的是哪個key,如未指定則會使用默認策略生成的key;condition表示清除操作發生的條件。如果要清除所有緩存可使用屬性 allEntries=true
手動添加、獲取、刪除緩存
上面的一些示例通過注解來進行緩存操作,有時候我們需要在一些方法里對緩存進行操作增刪改查:
1.從緩存中獲取數據
假設上面示例2中向名為 “caffeinSet_Value”的緩存里加入的鍵是8,值是"8是偶數!!"。
下面手動獲取此緩存:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Autowired CacheManager cacheManager; public String caffeinGetValue() { Cache cache = cacheManager.getCache( "caffeinSet_Value" ); //獲取緩存名稱。name為caffeinSetValue String name = cache.getName(); //獲取caffeinSetValue緩存里建是8的緩存 Cache.ValueWrapper value = cache.get( 8 ); String str = "" ; if ( null != value) { //獲取值,8是偶數!! str = String.valueOf(value.get()); } return str; } |
2.向緩存中添加數據
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@Autowired CacheManager cacheManager; public String caffeinPutValue() { Cache cache = cacheManager.getCache( "caffeinSet_Value" ); //獲取緩存名稱。name為caffeinSetValue String name = cache.getName(); /* //向緩存中put數據。如果不存在key是20的才會加入 cache.putIfAbsent(number, "添加測試"); */ //向緩存中put數據。如果存在key是20的會覆蓋原來的數據 cache.put( 20 , "20是偶數!!" ); return "成功" ; } |
3.刪除緩存中的數據
刪除caffeinSet_Value緩存中的某條緩存:
1
2
3
4
5
6
7
8
9
10
|
@Autowired CacheManager cacheManager; public String caffeinDeleteValue() { Cache cache = cacheManager.getCache( "caffeinSet_Value" ); //獲取緩存名稱。name為caffeinSetValue String name = cache.getName(); //只有20這條數據存在才會刪除 boolean bo = cache.evictIfPresent( 20 ); return String.valueOf(bo); } |
刪除caffeinSet_Value緩存中的所有緩存:
1
2
3
4
5
6
7
8
9
10
|
@Autowired CacheManager cacheManager; public String caffeinDeleteAllValue() { Cache cache = cacheManager.getCache( "caffeinSet_Value" ); //獲取緩存名稱。name為caffeinSetValue String name = cache.getName(); //刪除caffeinSet_Value中的所有緩存 boolean bo = cache.invalidate(); return String.valueOf(bo); } |
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/qq_33697094/article/details/114968105