Java 實(shí)現(xiàn)緩存的三種方式及問題匯總
Java 實(shí)現(xiàn)緩存的三種方式
一、HashMap實(shí)現(xiàn)緩存
? 可以實(shí)現(xiàn)簡(jiǎn)單的本地緩存,但是實(shí)際開發(fā)中不推薦,我們可以簡(jiǎn)單模擬一下緩存的實(shí)現(xiàn),
Step-1:實(shí)現(xiàn)一個(gè)緩存管理類
public class LocalCache {
public static HashMap<String,String> cache = new HashMap<>();
static {
String name = UUID.randomUUID().toString();
LocalCache.cache.put(String.valueOf(1),name);
System.out.println("id為1的數(shù)據(jù)添加到了緩存");
}
}
// 類中有 `static` 修飾的靜態(tài)代碼塊,當(dāng)類被加載的時(shí)候就會(huì)執(zhí)行,如有不懂的可以如下博客
// https://blog.csdn.net/weixin_62636014/article/details/136851287
Tips:我們?cè)?code>static中完成了對(duì)緩存的初始化,你可以往緩存里面放入初始數(shù)據(jù)。
Step-2:將緩存管理類交給 Spring 進(jìn)行管理
@Component
public class LocalCache {
public static HashMap<String,String> cache = new HashMap<>();
static {
String name = UUID.randomUUID().toString();
LocalCache.cache.put(String.valueOf(1),name);
System.out.println("id為1的數(shù)據(jù)添加到了緩存");
}
@PostConstruct
public void init() {
String name = UUID.randomUUID().toString();
LocalCache.cache.put(String.valueOf(2),name);
System.out.println("id為2的數(shù)據(jù)添加到了緩存");
}
}
Tips:在將緩存管理類交給了Spring進(jìn)行管理后,在方法上加入@PostConstruct,可以使方法默認(rèn)執(zhí)行,注意該注解不是Spring框架提供,僅僅是由Java JDK提供的,主要是作用于Servlet生命周期的注解,實(shí)現(xiàn)的是在Bean初始化之前自定義操作
@PostConstruct 方法在 Bean初始化中的執(zhí)行順序
Constructor(構(gòu)造方法)@Autowired(依賴注入)@PostConstruct(注釋的初始化方法)
Step-3:編寫接口測(cè)試緩存
@RequestMapping("test")
public String test(Long id) {
String name = LocalCache.cache.get(String.valueOf(id));
if (name != null) {
System.out.println("緩存中存在,查詢緩存");
System.out.println(name);
return name;
}
System.out.println("緩存中不存在,查詢數(shù)據(jù)庫");
// 查詢數(shù)據(jù)庫操作后,queryDataName方法沒有寫了;
// 大家可以自己配一下Mybatis和JDBC進(jìn)行數(shù)據(jù)庫查詢,達(dá)到效果是從庫中查出來 name;
name = queryDataName(id);
System.out.println(name);
LocalCache.cache.put(String.valueOf(id),name);
return name;
}
public String queryDataName(Long id) {
String name = UUID.randomUUID().toString();
return name;
}Step-4:結(jié)果展示
? 這個(gè)是控制臺(tái)輸出,每個(gè)人的隨機(jī) UUID 不一致,我這個(gè)只是一個(gè)樣例
id為1的數(shù)據(jù)添加到了緩存
id為2的數(shù)據(jù)添加到了緩存
緩存中存在,查詢緩存
e2eadabe-3c42-4732-b465-e085ea5faf96
緩存中不存在,查詢數(shù)據(jù)庫
942ffe92-454f-4046-87e5-53e8b951d2a1
二、guava local cache 實(shí)現(xiàn)
Tips:Guava是Java工具包,Guava Cache是一套非常完善的本地緩存機(jī)制(JVM緩存),工具類就是封裝平常常用的方法,不需要你重復(fù)造輪子,節(jié)省開發(fā)人員時(shí)間,我們一般需要知道怎么使用。其設(shè)計(jì)來源于CurrentHashMap,可以按照多種策略來清理存儲(chǔ)在其中的緩存值且保持很高的并發(fā)讀寫性能。
Guava提供以下方面的能力
- 集合 [
collections]- 緩存 [
caching]- 原生類型支持 [
primitives support]- 并發(fā)庫 [
concurrency libraries]- 通用注解 [
common annotations]- 字符串處理 [
string processing]I/O等等。
Step-1:導(dǎo)入guava 依賴
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version>
</dependency>Step-2:使用guava創(chuàng)建簡(jiǎn)單緩存管理類
為了方便展示,這里面使用了5 秒的緩存保留時(shí)間。
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class GuavaLocalCache{
private Cache<String,String> fiveSecondCache = CacheBuilder.newBuilder()
//設(shè)置緩存初始大小,應(yīng)該合理設(shè)置,后續(xù)會(huì)擴(kuò)容
.initalCapacity(10)
//最大值
.maximumSize(100)
//并發(fā)數(shù)設(shè)置
.concurrencyLevel(5)
//緩存過期時(shí)間,寫入后5秒鐘過期
.expireAfterWrite(5,TimeUnit.SECONDS)
//統(tǒng)計(jì)緩存命中率
.recordStats()
.build()
public Cache<String,String> getFiveSecondCache() {
return fiveSecondCache;
} // 這里就是拿到緩存對(duì)象。
public void setFiveSecondCache(Cache<String,String> fiveSecondCache) {
this.fiveSecondCache = fiveSecondCache;
}
}Step-3:使用 guava cache,并嘗試統(tǒng)計(jì)命中率
public class test {
@Autowired
private GuavaLocalCache guavaLocalCache;
@RequestMapping("guavaTest")
public String guavaTest(Long id) {
// 獲取緩存
Cache<String,String> fiveSecondCache = guavaLocalCache.getFiveSecondCache();
// 從緩存中獲取對(duì)象
String nameCache = fiveSecondCache.getIfPresent(String.valueOf(id));
// 緩存中存在
if (nameCache != null) {
System.out.println("緩存命中:"+ nameCache + "," + getCacheStats(fiveSecondCache));
return nameCache;
}
// 將數(shù)據(jù)存入緩存
System.out.println("緩存未命中," + getCacheStats(fiveSecondCache));
nameCache = id + "-" + UUID.randomUUID().toString();
fiveSecondCache.put(String.valueOf(id),nameCache);
return nameCache;
}
public String getCacheStats(Cache<String,String> cahce) {
CacheStats stats = cache.stats();
return "緩沖命中率:"+stats.hitRate() +" 被清除緩沖數(shù):" + stats.evictionCount();
}
}三、使用redis實(shí)現(xiàn)緩存
Tips:Redis(全稱:Remote Dictionary Server遠(yuǎn)程字典服務(wù))是一個(gè)開源的使用ANSI C語言 編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫 。Redis一般被用來做緩存用的,它實(shí)際上也是一種數(shù)據(jù)庫(非關(guān)系型數(shù)據(jù)庫),可以對(duì)經(jīng)常使用到的數(shù)據(jù)進(jìn)行存儲(chǔ),也就是大家所說的緩存。官方給出的數(shù)據(jù)是,Redis能達(dá)到10w+的QPS( 每秒查詢速度 ) 。
Tips: 為什么Redis的速度比Mysql等這種數(shù)據(jù)快呢?? 因?yàn)?
Redis存儲(chǔ)的是key-values格式的數(shù)據(jù),時(shí)間復(fù)雜度是O(1),即直接通過key查詢對(duì)應(yīng)的value。 而如Mysql數(shù)據(jù)庫,底層的實(shí)現(xiàn)是B+樹,時(shí)間復(fù)雜度是O(logn)。? 最重要的一點(diǎn)是,數(shù)據(jù)庫的數(shù)據(jù)是存儲(chǔ)在磁盤中的,而
Redis是存儲(chǔ)在內(nèi)存當(dāng)中的,它們的速度差距不言而喻。但Redis也支持持久化存儲(chǔ)
Step-1:導(dǎo)入Redis 依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>在 SpringBoot 配置文件中加入設(shè)置,我使用的是yml 形式的文件,如果沒有密碼的話不填就好了
redis:
# IP地址
host: XXX.XXX.XXX.XXX
# 密碼
password: XXXXXXXX
# 端口,默認(rèn)為6379
port: 6379
# 數(shù)據(jù)庫索引
database: 0
# 連接超時(shí)時(shí)間
timeout: 10s
lettuce:
pool:
# 連接池中的最小空閑連接
min-idle: 1
# 連接池中的最大空閑連接
max-idle: 8
# 連接池的最大數(shù)據(jù)庫連接數(shù)
max-active: 8
# #連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制)
max-wait: -1msStep-2:編寫測(cè)試接口
public class TestRedis{
// 下面StringRedisTemplate 是一個(gè)繼承自 RedisTemplate的類
@Autowired
private StringRedisTemplate stringRedisTemplate;
@RequestMapping("/redisTest")
public String redisCacheTest(Long id){
String name = stringRedisTemplate.opsForValue().get(String.valueOf(id));
if (name != null){
System.out.println("緩存中存在,查詢緩存");
System.out.println(name);
return name;
}
System.out.println("緩存中不存在,查詢數(shù)據(jù)庫");
name = id + "-" + UUID.randomUUID().toString();
System.out.println(name);
stringRedisTemplate.opsForValue().set(String.valueOf(id),name);
return name;
}
}Step-3:進(jìn)行接口測(cè)試,并使用Redis DeskTop Manager 進(jìn)行查看
參考文章
- 【java緩存、redis緩存、guava緩存】java中實(shí)現(xiàn)緩存的幾種方式_java緩存cache-CSDN博客
- 一篇文章搞定 Redis 基礎(chǔ)知識(shí) - 知乎 (zhihu.com)
- Java本地緩存技術(shù)選型(Guava Cache、Caffeine、Encache) - 掘金 (juejin.cn)
- MemCache原理超詳細(xì)解讀(僅學(xué)習(xí)) - 知乎 (zhihu.com)
- PostConstruct注解詳細(xì)使用說明及理解-CSDN博客
- PostConstruct (Java Platform SE 8 ) (oracle.com)
- Java開發(fā)利器Guava Cache之使用篇 - 掘金 (juejin.cn)
- Google guava 工具類的介紹和使用 - 掘金 (juejin.cn)
- Redis詳細(xì)介紹(精簡(jiǎn)版)_redis 服務(wù) 精簡(jiǎn)-CSDN博客
- 初識(shí)Redis,看這一篇就夠了
到此這篇關(guān)于Java 實(shí)現(xiàn)緩存的三種方式問題匯總的文章就介紹到這了,更多相關(guān)Java 實(shí)現(xiàn)緩存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Feign切換client到okhttp無法生效的坑(出現(xiàn)原因說明)
這篇文章主要介紹了解決Feign切換client到okhttp無法生效的坑(出現(xiàn)原因說明),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Maven項(xiàng)目打包成war包部署到Tomcat的方法
這篇文章主要介紹了Maven項(xiàng)目打包成war包部署到Tomcat的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-06-06
MyBatis批量插入幾千條數(shù)據(jù)為何慎用foreach
這篇文章主要介紹了MyBatis批量插入幾千條數(shù)據(jù)為何慎用foreach問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
idea的easyCode的 MybatisPlus模板的配置詳解
這篇文章主要介紹了idea的easyCode的 MybatisPlus模板的配置詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Java Flink窗口觸發(fā)器Trigger的用法詳解
Trigger(窗口觸發(fā)器)決定了窗口(由 WindowAssigner 產(chǎn)生)什么時(shí)候調(diào)用窗口處理函數(shù)??梢愿鶕?jù)指定的時(shí)間或數(shù)據(jù)元素條件來決定什么時(shí)候觸發(fā)。本文將詳細(xì)講講其用法,需要的可以參考一下2022-07-07
Java使用EasyExcel動(dòng)態(tài)修改模板Sheet名稱的具體方案
在使用 EasyExcel 通過模板導(dǎo)出時(shí),模板中的 sheet 名稱通常是固定的,如果我們希望在導(dǎo)出時(shí)根據(jù)業(yè)務(wù)需要 動(dòng)態(tài)修改 sheet 名稱,可以通過自定義 SheetWriteHandler 完成,所以本文介紹了Java使用EasyExcel動(dòng)態(tài)修改模板Sheet名稱的具體方案,需要的朋友可以參考下2025-12-12
springBoot定時(shí)任務(wù)處理類的實(shí)現(xiàn)代碼
這篇文章主要介紹了springBoot定時(shí)任務(wù)處理類,需要的朋友可以參考下2018-06-06
SpringSecurity+Redis認(rèn)證過程小結(jié)
這篇文章主要介紹了SpringSecurity+Redis認(rèn)證過程小結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01

